題目意思:
給5組數,每組含n個數(n<=200),在5組數中各選一個,問是否存在一種組合使這5個數的和為0。
解題思路:
這題數據很強,o(n^3*lgn過不了)
對於在兩組數各選一個使得和為定值,有一種貪心的算法,時間復雜度為(n*lgn,實際上就是排序的算法時間復雜度)。
所以可以把第二組和第三組數合並組合40000個數作為第二組,第四組和第五組合並成40000個數作為第三組。
分別排序。
1、然後枚舉第一組,初始時用p指針指向第二組中的第一個數,q指針指向第三組的最後一個數,以第二組為基准。
2、當三數大於0時,說明q指針後面的所有數與p指針後面的數肯定不行,大於當前的和值,同時說明p指針後面的只可能和q指針前面的湊,所以q指針往前移。
3、當三數小於0時,說明p與當前的q不行,p與q後面的也不行(由上一步得),p與q前面的更不行。所以p只能往後移。
貪心思想,所以最多只移動了40000+40000次。
所以總的時間復雜度為o(n^3).
代碼:
<SPAN style="FONT-SIZE: 18px">#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #define eps 1e-6 #define INF 0x1f1f1f1f #define PI acos(-1.0) #define ll __int64 #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; /* freopen("data.in","r",stdin); freopen("data.out","w",stdout); */ ll s1[41000],s2[41000]; ll sa[6][210]; int cnt1,cnt2,n; int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=5;i++) for(int j=1;j<=n;j++) scanf("%I64d",&sa[i][j]); //sort(sa[1]+1,sa[1]+n+1); cnt1=cnt2=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { s1[++cnt1]=sa[2][i]+sa[3][j]; //把2、3組合並和把4、5組合並 s2[++cnt2]=sa[4][i]+sa[5][j]; } sort(s1+1,s1+cnt1+1); sort(s2+1,s2+cnt2+1); int t=1; //離散化一下,去掉相同的 for(int i=2;i<=cnt1;i++) if(s1[i]!=s1[i-1]) s1[++t]=s1[i]; cnt1=t; t=1; for(int i=2;i<=cnt2;i++) if(s2[i]!=s2[i-1]) s2[++t]=s2[i]; cnt2=t; /* if(sa[1][n]+s1[cnt1]+s2[cnt2]<0) { printf("Yes\n"); continue; }*/ bool ans=false; for(int i=1;i<=n&&!ans;i++) { //if(sa[1][i]+s1[1]+s2[1]>0) // break; for(int p=1,q=cnt2;p<=cnt1&&q>=1;) //貪心思想 { ll tt=sa[1][i]+s1[p]+s2[q]; if(tt==0) { ans=true; break; } else if(tt>0) q--; else p++; } } if(ans) printf("Yes\n"); else printf("No\n"); } return 0; } </SPAN>