题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5000
题意:
某君拥有n个属性值,某天闲着无聊克隆了若干个自己,若克隆体A的每格属性均大于等于克隆体B,则克隆体B会被杀死,给出n个属性值的上限,问最多能存活几个克隆体
思路:
数据量极小的问题一般都是DP = = 数据量极小的题一般都是DP = = 数据量极小的题一般都是DP = =
题目备注了所有属性上限之和小于2000,先观察下测试数据
1 5 活下来的有六个集合的可能 {(5)} {(4)} {(3)} {(2)} {(1)} {(0)}
2 8 6 活下来的有三个集合的可能 {(0,6)(1,5)(2,4)(3,3)(4,2)(5,1)(6,0)} {(1,6)(2,5)(3,4)(4,3)(5,2)(6,1)(7,0)} {(2,6)(3,5)(4,4)(5,3)(6,2)(7,1)(8,0)}
观察到其实活下来的每个集合的每个克隆体,其实属性和是一样的,再多算几组数据加上大胆猜测,不难发现属性和为sum/2的集合始终是最终答案,则问题转变成,给定ΣT[i]个数,问有多少种可能组成和为sum/2,01背包问题
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MOD = 1e9+7;
long long dp[2005][1005];
int arr[2005];
int main(){
int total;
int i,n,j,k;
cin>>total;
while (total--){
int sum = 0;
scanf("%d",&n);
for (i=0;i<n;++i){
scanf("%d",arr+i);
sum += arr[i];
}
sum /= 2;
memset(dp,0,sizeof(dp));
for (i = 0;i<=arr[0];++i)
dp[0][i] = 1;
for (i=1;i<n;++i){
for (j=0;j<=arr[i];++j){
for (k=sum-j;k>=0;--k){
dp[i][k+j] += dp[i-1][k];
dp[i][k+j] %= MOD;
}
}
}
cout<<dp[n-1][sum]<<endl;
}
return 0;
}