和为0的4个值

试题描述ios

 给定4个n(1<=n<=4000)元素集合A,B,C,D,要求分别从中选取一个元素a,b,c,d,使得a+b+c+d=0。问:有多少种选法?ide

例如,A={-45,-41,-36,26,-32,100000},B={22,-27,53,30,-38,-54},C={42,56,-37,-75,-10,-6},D={-16,30,77,-46,62,45},则有5种选法:(-45,-27,42,30),(26,30,-10,-46),(-32,22,56,-46),(-32,30,-75,77),(-32,-54,56,30)。测试

输入优化

第一行包括一个整数 T,表示测试数据组数
而后每组数据之间都以一个空行
每组数据中,每一行表示一个元素集合(以空行结束一个集合)
数据保证每组数据中每一个元素集合数量相同spa

输出3d

对于每组数据,一个整数表示一共有多少种选法,以空行结束一组数据code

输入示例blog

1

6
-45 22 45 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45排序

输出示例内存

5

其余说明

试题来源:UVA1152

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

讲解:

由于n<=4000,因此得从四重循环得优化,咱们只须要将a,b,c,d排序去重,将a,b中全部组合存下来放入c,d的全部组合中二分查找。

代码实现:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; 
const int xx=2010;
int a[xx],b[xx],c[xx],d[xx],sum1[xx*xx],sum2[xx*xx],n,dex1,dex2,ans;
bool ff(int l,int r,int s)//二分查找(略) 
{
    int i,j,mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(sum2[mid]==s) return true;
        else if(sum2[mid]>s) r=mid;
        else l=mid+1;
    }
    return false;
}
int main()
{ 
    int i,j,t;
    scanf("%d",&t);
    while(t!=0)
    {
        ans=0;
        dex1=0;
        dex2=0; 
        t--;
        scanf("%d",&n);
        for(i=0;i<n;i++) scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
        sort(a,a+n); //排序,便于去重
        sort(b,b+n);
        sort(c,c+n);
        sort(d,d+n);
        for(i=0;i<n;i++) 
        {
            if(i!=0 && a[i]==a[i-1]) continue; //去重 
            for(j=0;j<n;j++) 
            {
                if(j!=0 && b[j]==b[j-1]) continue;//去重 
                sum1[dex1++]=a[i]+b[j];//将a+b的值存进sum里 
            }
        }
        sort(sum1,sum1+dex1);//sum排序 
        for(i=0;i<n;i++)
        {
            if(i!=0 && c[i]==c[i-1]) continue;//去重 
            for(j=0;j<n;j++)
            {
                if(j!=0 && d[j]==d[j-1]) continue;//去重 
                sum2[dex2++]=c[i]+d[j];
            }
        }
        sort(sum2,sum2+dex2);
        for(i=0;i<dex1;i++) if(ff(0,dex2,-sum1[i])) ans++;//把 -c[i]-d[j]的值在sum里二分查找 
        cout<<ans<<endl;
    }
    return 0;
}
View Code

若是内存超限(mle)咱们能够牺牲时间:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; 
const int xx=4010;
int a[xx],b[xx],c[xx],d[xx],sum[xx*xx],n,dex,ans;
bool ff(int l,int r,int s)//二分查找(略) 
{
    int i,j,mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(sum[mid]==s) return true;
        else if(sum[mid]>s) r=mid;
        else l=mid+1;
    }
    return false;
}
int main()
{ 
    int i,j,t;
    scanf("%d",&t);
    while(t!=0)
    {
        ans=0;
        dex=0;
        t--;
        scanf("%d",&n);
        for(i=0;i<n;i++) scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
        sort(a,a+n); //排序,便于去重
        sort(b,b+n);
        sort(c,c+n);
        sort(d,d+n);
        for(i=0;i<n;i++) 
        {
            if(i!=0 && a[i]==a[i-1]) continue; //去重 
            for(j=0;j<n;j++) 
            {
                if(j!=0 && b[j]==b[j-1]) continue;//去重 
                sum[dex++]=a[i]+b[j];//将a+b的值存进sum里 
            }
        }
        sort(sum,sum+dex);//sum排序 
        for(i=0;i<n;i++)
        {
            if(i!=0 && c[i]==c[i-1]) continue;//去重 
            for(j=0;j<n;j++)
            {
                if(j!=0 && d[j]==d[j-1]) continue;//去重 
                if(ff(0,dex,-c[i]-d[j])) ans++;//把 -c[i]-d[j]的值在sum里二分查找 
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code
相关文章
相关标签/搜索