阿汤的数组
题目描述
阿汤同学为了准备下学期的 ACM-ICPC,刷了很多的题目,他觉得自己已经比较厉害了,于是想出个题目考考你。现在他给你一个数组 A,问你是否能将该数组划分成数组 B、C 使得 B 数组的平均数和C 数组的平均数相等,数组 B 和 C 都不能为空。
输入描述:
从标准输入读入数据。 输入包含多组数据,第一行一个整数 T 代表数据组数。接下来依次描述每组数据,对于每组数据: 第一行输入正整数 N,第二行输入 N 个非负整数 1≤|A|≤30 (数组 A 的长度范围在 1 到 30 之间 ) 0≤A[i]≤10000 (数组 A 中的元素)
输出描述:
输出到标准输出。 对于每组数据,输出一行: 如果能划分成满足题目要求的数组 B 和 C 则输出 yes,否则输出no
示例1
输入
1 8 1 2 3 4 5 6 7 8
输出
yes
说明
样例说明:将数组 A 划分成【1,4,5,8】和【2,3,6,7】,平均数为 4.5
理解:即可理解成一个背包问题,只要找出背包中平均数跟全部的平均数想等的就可以啦。。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 33;
int t, n, s[maxn];
double sum;
bool dp[310005][33];
bool solve()
{
int i, j, z;
memset(dp, 0, sizeof(dp));
dp[0][0] = true;
int smax = 0;
for(i = 1; i <= n; i++) //背包外层循环。。
{
for(j = smax; j >= 0; j--) //背包每个只能装1次
{
for(z = 0; z < n - 1; z++) //取了z个包了。。。
{
if(dp[j][z])
{
int k = j+s[i];
dp[k][z+1] = true;
smax = max(smax, k);
if(fabs(k*1.0/(z+1) - sum)<= 0.0000000001)
{
return 1;
}
}
}
}
}
return false;
}
int main()
{
scanf("%d", &t);
while(t--)
{
sum = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &s[i]), sum += s[i];
sum /= n;
if(solve()) puts("yes");
else puts("no");
}
return 0;
}