【问题描述】
给定4个含n(n<=4000)个元素的集合A,B,C,D,要求分别从中选取一个元素a,b,c,d,使得a+b+c+d=0。问有多少种选法。
【输入格式】
第一行为整数n,表示集合元素个数,接下来的4行,每行表示一个集合。
【输出格式】
一个整数,表示方案数。
【输入样例】
6
-45 -41 -36 -36 26 -32
22 -27 53 30 -38 -54
42 56 -37 -75 -10 -6
-16 30 77 -46 62 45
【输出样例】
5
【样例解释】
输入的集合为:
A={-45,-41,-36,-36,26,-32},
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)
【数据范围】
1<=n<=4000 集合元素为-2^28~2^28之间的值。
【来源】
《算法竞赛》第二版 237页 uva 1152
用中途相遇的思想,先枚举前2个数的和(用map可以更快速的查找并记录个数),然后再枚举后面2个,再进行查找就可以了。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=4005;
const int inf=200000000;
map<int,int>m;
int a[maxn],n,d[maxn],c[maxn],b[maxn];
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
scanf("%d",&d[i]);
}
int main()
{
//freopen("in.txt","r",stdin);
init();
int t=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int k=a[i]+b[j];
if(m[k]>0) m[k]++;
else m[k]=1;
}
long long ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int k=c[i]+d[j];
ans+=m[-k];
}
cout<<ans;
return 0;
}
本篇介绍一种高效算法解决从四个集合中各选一个元素使它们的和为零的问题,通过预处理两个集合的和并使用哈希表进行查找匹配。

被折叠的 条评论
为什么被折叠?



