ACM题 关于n个数据,最后选出3个构成三角形,要求边长最大
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM题 关于n个数据,最后选出3个构成三角形,要求边长最大相关的知识,希望对你有一定的参考价值。
Description
可怜的lpx终于在别人的帮助下追上了aqx,可是他那瘦弱的身体想要去强行从aqx那里抢回烟那是不可能的。aqx看着可怜的lpx实在不忍心继续欺负他,便随手扔出来一堆长短不一的木棍,让lpx从中挑出来三根木棍,组成一个三角形,如果这个三角形的周长最大,那么aqx将把烟还给lpx。哎,可怜的lpx。。。
Input
多组数据,每组数据一个n(5<= n <=10^6),代表有n根木棍。
接下来n个整数Xi,代表第i根木棍的长为Xi (1<=Xi<=10^6)。
Output
能组成最大的三角形周长(保证有解)
Sample Input
4
1 2 3 4
Sample Output
9
Hint
我是这么想的,先排序,从大到小排序,然后再取3条边。
int main()
int n,*a,i,j,k,first,second,third,flag=1;
while(cin>>n) a=(int *)malloc(sizeof(int)*n);
for(i=0;i<n;i++) cin>>*(a+i);
fenkai(&a[0],0,n-1,n);//排序 分治算法
for(i=0;i<n&&flag;i++)
for(j=i+1;j<n&&flag;j++)
for(k=j+1;k<n;k++)
if(a[i]-a[j]<a[k]) cout<<a[i]+a[j]+a[k]<<endl; flag=0;break;
else break;
flag=1;
free(a);
return 0;
然后看一下主算法。你的算法是O(n^3)的,对于n=100000的数据,肯定严重超时。
对于n=100000的数据,必须用O(nlogn)以下级别的算法解决。 这个题是贪心,不是搜索。
说一下思路。
先从大到小排序,然后取最大的三条边判断三角形的条件。如果不能,则用第2大、第3大、第4大的三条边判断,如果还不行就用用第3大、第4大、第5大的三条边判断。什么时候可以了,三边之和就是要的周长最大值。
证明:
假设我有一个从大到小排好序的数组a[0...n-1]. 对于最大的三条边,如你所说,这里判断三角形的唯一条件就是a[0]<a[1]+a[2]. 如果它不成立即a[0]>=a[1]+a[2],则对于任何i,j, (i>=1, j>=2, i≠j), 有a[1]>=a[i], a[2]>=a[j],因此a[0]>=a[i]+a[j]. 换句话说,如果最大的一条边不能跟第二大、第三大的两条边组成三角形,就一定不能与其他边组成三角形。因此这个最大边就应该被舍弃(想象这根棍子被扔了)。在剩下的n-1个棍子里的最大的三条边继续上面的算法,直到找到符合条件的三角形为止。证毕。 参考技术A 周长最大也即是三条边最大。 用排序就好了吧,然后从大到小选三条木棍,只要能组成三角形那它的周长就是最大的。
组成三角形的条件是,任意二边的和大于第三边。看你的程序,貌似只判断了其中二边的差小于第三边就可以了?给你个例子。 1,2 ,4追问
我那个不是已经从大到小排序了的么,所以我那个两边之差是最大边-第二大边《第三大边的。。。。不应该就可以是三角形了么
追答那最终答案是WA?那你再确认下是不是排序有问题了。 这个思路应该是没问题的。
追问真的不好意思。谢谢您的帮助。。。。。。。。可是好评只能给一个、、、、、
热身题
1.三角形
- 题目大意:n根棍子,棍子i的长度ai,选出3根棍子组成周长尽可能长的三角形,输出最大周长,无法组成三角形则输出0
- 限制条件:3≤n≤100,1≤ai≤106
- 做法1:很自然的可以想到穷举所有的方案,复杂度是O(n3)的,n的限制条件1s足够,这里介绍一种O(nlogn)的做法
- 做法2:将棍子按长度从大到小进行排序,判断长度最长的三根棍子能否构成三角形,如果可以则找到满足要求的解,相加即得到最大周长,如果不能构成三角形,说明最长的棍子不能与其他棍子构成三角形,丢弃它,在剩下的棍子里再进行判断,这样可以把复杂度控制在O(nlogn)+O(n)
- 代码:
1 #include <iostream> 2 #include <ctime> 3 #define random(l,r) (rand()%(r-l+1)+l) 4 using namespace std; 5 6 int n; 7 int * a; 8 9 void qsort(int, int); 10 void swap(int &, int &); 11 12 int main(int argc, char * argv[]) 13 { 14 bool flag = false; 15 srand((unsigned)time(NULL)); 16 cin >> n; 17 a = new int[n]; 18 for (int i=0; i<n; i++) 19 { 20 cin >> a[i]; 21 } 22 qsort(0,n-1); 23 for (int i=0; i<n-2; i++) 24 { 25 if (a[i]<a[i+1]+a[i+2]) 26 { 27 cout << a[i]+a[i+1]+a[i+2] << endl; 28 flag = true; 29 break; 30 } 31 } 32 if (!flag) cout << 0 << endl; 33 } 34 35 void qsort(int l, int r) 36 { 37 int i=l; 38 int j=r; 39 int mid=a[random(l,r)]; 40 do 41 { 42 while (a[i]>mid) i++; 43 while (a[j]<mid) j--; 44 if (i<=j) swap(a[i++],a[j--]); 45 } 46 while (!(i>j)); 47 if (l<j) qsort(l,j); 48 if (i<r) qsort(i,r); 49 } 50 51 void swap(int &x, int &y) 52 { 53 int t=x; 54 x=y; 55 y=t; 56 }
2.Ants (POJ1852)
- 原题如下:
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 24129 | Accepted: 9652 |
Description
Input
Output
Sample Input
2 10 3 2 6 7 214 7 11 12 7 13 176 23 191
Sample Output
4 8 38 207
- 题解:
- 最短时间很简单,所有蚂蚁往较近的一端走即可,这种情况下也不会发生两只蚂蚁相遇的情况,最短时间就是每只蚂蚁所走最短时间的最大值
- 对于最长时间,我们需要考虑两只蚂蚁相遇的情况,而事实上,两只蚂蚁相遇之后各自反向前进与两只蚂蚁相遇之后保持原样交错而过继续前进是等效的,因此可认为每只蚂蚁都是独立运动的,最长时间就是每只蚂蚁往较长一端走的时间的最大值
- 代码:
1 #include <iostream> 2 3 using namespace std; 4 5 template <typename T> 6 T minn(T, T); 7 8 template int minn<int>(int, int); 9 10 template <typename T> 11 T maxn(T, T); 12 13 template<> int maxn<int>(int, int); 14 15 int main(int argc, char * argv[]) 16 { 17 int k; 18 for (cin >> k; k>0; k--) 19 { 20 int l, n; 21 cin >> l >> n; 22 int * a = new int[n]; 23 for (int i=0; i<n; i++) cin >> a[i]; 24 int tmin=0, tmax=0; 25 for (int i=0; i<n; i++) 26 { 27 tmin=maxn(tmin,minn(a[i],l-a[i])); 28 tmax=maxn(tmax,maxn(a[i],l-a[i])); 29 } 30 cout << tmin << ‘ ‘ << tmax << endl; 31 } 32 return 0; 33 } 34 35 template <typename T> 36 T minn(T x, T y) 37 { 38 if (x<y) return x; 39 return y; 40 } 41 42 template <typename T> 43 T maxn(T x, T y) 44 { 45 if (x>y) return x; 46 return y; 47 } 48 49 template<> int maxn<int>(int x, int y) 50 { 51 if (x>y) return x; 52 return y; 53 }
3.增加难度的抽签问题
- 题目大意:检查数组k中是否存在ka+kb+kc+kd=m,要求将四重循环的穷举算法进行优化,四重循环如下:
for (int a = 0; a < n; a++) { for (int b = 0; b < n; b++) { for (int c = 0; c < n; c++) { for (int d = 0; d < n; d++){ if (k[a]+k[b]+k[c]+k[d] == m) { f = true; } } } } }
- 优化1:考虑最内侧关于d的循环,做的事就是检查是否有d使得ka+kb+kc+kd = m,通过移相,可得kd = m-ka-kb-kc ,也即是说检查数组k中所有元素,判断是否有m-ka-kb-kc ,于是得到三重循环+二分搜索的O(n3logn)的算法
- 优化2:继续优化1的思路,考虑内侧的两个循环,内测的两个循环是在检查是否有c和d使得kc+kd = m-ka-kb ,这种情况下只要预先枚举出kc+kd 所得的n2个数字(实际上在去除重复之后n(n+1)/2个数字就够了)并排好序,就可以继续利用二分搜索了,总的时间复杂度是O(n2logn)
- 代码:(就放个二分查找的模板好了,枚举k[c]+k[d]的时候把它放在k[c*n+d]里就好了→_→)
1 #include <iostream> 2 #define random(l,r) (rand()%(r-l+1)+l) 3 4 using namespace std; 5 6 int n,m; 7 int * k; 8 9 bool binary_search(int); 10 void qsort(int, int); 11 12 int main(int argc, char * argv[]) 13 { 14 cin >> n >> m; 15 k = new int[n]; 16 for (int i=0; i<n; i++) 17 { 18 cin >> k[i]; 19 } 20 qsort(0,n-1); 21 for (int i=0; i<n; i++) 22 { 23 cout << k[i] << ‘ ‘; 24 } 25 cout << endl; 26 cout.setf(ios_base::boolalpha); 27 cout << binary_search(m) << endl; 28 } 29 30 bool binary_search(int x) 31 { 32 int l=0, r=n-1; 33 while (l<=r) 34 { 35 int mid = (l+r)/2; 36 if (k[mid]==x) return true; 37 else if (k[mid]<x) l=mid+1; 38 else r=mid-1; 39 } 40 return false; 41 } 42 43 void qsort(int l, int r) 44 { 45 int i=l, j=r; 46 int mid=k[random(l,r)]; 47 do 48 { 49 while (k[i]<mid) i++; 50 while (k[j]>mid) j--; 51 if (i<=j) 52 { 53 int temp=k[i]; 54 k[i]=k[j]; 55 k[j]=temp; 56 i++;j--; 57 } 58 } 59 while (i<=j); 60 if (i<r) qsort(i,r); 61 if (j>l) qsort(l,j); 62 }
以上是关于ACM题 关于n个数据,最后选出3个构成三角形,要求边长最大的主要内容,如果未能解决你的问题,请参考以下文章