Trouble
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5388 Accepted Submission(s): 1494
Problem Description
Hassan is in trouble. His mathematics teacher has given him a very difficult problem called 5-sum. Please help him.
The 5-sum problem is defined as follows: Given 5 sets S_1,...,S_5 of n integer numbers each, is there a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0?
The 5-sum problem is defined as follows: Given 5 sets S_1,...,S_5 of n integer numbers each, is there a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0?
Input
First line of input contains a single integer N (1≤N≤50). N test-cases follow. First line of each test-case contains a single integer n (1<=n<=200). 5 lines follow each containing n integer numbers in range [-10^15, 1 0^15]. I-th line denotes set S_i for 1<=i<=5.
Output
For each test-case output "Yes" (without quotes) if there are a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0, otherwise output "No".
Sample Input
2
2
1 -1
1 -1
1 -1
1 -1
1 -1
3
1 2 3
-1 -2 -3
4 5 6
-1 3 2
-4 -10 -1
Sample Output
No
Yes
题目大意:给你5行每行n个数,问你是否可以在每行中取出一个数,让a1+a2+a3+a4+a5=0。
解题思路:开始写了搜索,但是一直超时。然而超时好像是必然的,没办法剪枝。其实可以将前1、2行合成一行a,将3、4行合成一行b,从小到大排序。枚举剩下的最后一行c,枚举a,逆序枚举b。贪心思想在如果b的当前值跟a和c的和小于0,那么可以直接让a的指针加一,如果大于0,可以让b的指针减一,如果逆序遍历完b或正序遍历完a以后还没找到,那么就继续枚举c。
#include<bits/stdc++.h> using namespace std; typedef long long INT; INT Map[6][210]; INT a[42000]; INT b[42000]; INT c[210]; int main(){ int t,n; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=5;i++){ for(int j=0;j<n;j++){ scanf("%lld",&Map[i][j]); } } int na=0,nb=0,nc=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ a[na++]=Map[1][i]+Map[2][j];//合并1、2行 b[nb++]=Map[3][i]+Map[4][j];//合并3、4行 } } int nn=n*n; sort(a,a+nn); //递增排序 sort(b,b+nn); //递增排序 na=1,nb=1,nc=1; for(int i=1;i<nn;i++){ //去重 if(a[i]!=a[i-1]){ a[na++]=a[i]; } } for(int i=1;i<nn;i++){ //去重 if(b[i]!=b[i-1]){ b[nb++]=b[i]; } } c[0]=Map[5][0]; for(int i=1;i<n;i++){ //去重 if(Map[5][i]!=Map[5][i-1]){ c[nc++]=Map[5][i]; } } int flag=0; for(int i=0;i<nc&&(!flag);i++){ //n的复杂度 for(int j=0,k=nb-1;k>=0&&j<na; ){//n*n的复杂度 INT cc=c[i]+a[j]+b[k]; if(cc<0){ //降低复杂度。模拟跳出一层循环 j++; }else if(cc==0){ flag=1; break; }else{ k--; } } } if(flag){ puts("Yes"); }else { puts("No"); } } return 0; }