HDU 4334——Trouble——————【贪心&水题】

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?
 
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;
}

  

原文地址:https://www.cnblogs.com/chengsheng/p/4758368.html