SOJ 3172: Fisherman http://acm.scu.edu.cn/soj/problem.action?id=3172
题意:给出n个数,从这n个数中选出任意一些求和,求解有多少种不同的和。
分析:考虑0-1背包模型,定义dp[i][j]为使用前i个数,和j是否存在,若存在则为1,否则为0. 那么我们有状态转移方程
dp[i][j]=max{dp[i-1][j],dp[i-1][j-num[i]].
也即是dp[j]=max{dp[j],dp[j-num[i]]}. 初始化dp[0]=1, 其他为0. 代码如下:
#include<iostream> #include<cstring> #include<algorithm> using namespace std; int num[32]; int dp[30002]; int main() { int T, N; scanf("%d", &T); int i, j; int sum; int minNum; int result; while (T--) { scanf("%d", &N); sum = 0; minNum = 1001; for (i = 0; i < N; i++) { scanf("%d", &num[i]); sum += num[i]; if (num[i] < minNum) minNum = num[i]; } memset(dp, 0, sizeof(dp)); dp[0] = 1; for (i = 0; i < N; i++) for (j = sum; j >= num[i]; j--) dp[j] = max(dp[j], dp[j - num[i]]); result = 0; for (i = minNum; i <= sum; i++) if (dp[i]) result++; printf("%d\n", result); } return 0; }