和爲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
相關文章
相關標籤/搜索