http://acm.hdu.edu.cn/showproblem.php?pid=5616
题意:有n个物品,每个重量为w[i],有一个天平,你可以把物品放在天平的左边或者右边,接下来m个询问,问是否能用这些物品称出x的重量。
思路:如果只能放一边,那就是很简单的背包DP,现在考虑要放在左右两边,那么只需要逆着来做一遍就好了。因为如果放在左边就不能放在右边了,因此要分开算。
初始状态dp[0][0] = 1.
if(dp[i-1][j+w[i]] == 1) dp[i][j] = 1。(j + w[i] <= sum)
if(dp[i-1][j-w[i]] == 1) dp[i][j] = 1。(j - w[i] >= 0)
可以用滚动数组优化。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 25 4 5 int dp[2][N*100], w[N]; 6 7 int main() { 8 int t; scanf("%d", &t); 9 while(t--) { 10 int n; scanf("%d", &n); 11 int sum = 0; 12 for(int i = 1; i <= n; i++) scanf("%d", &w[i]), sum += w[i]; 13 memset(dp, 0, sizeof(dp)); 14 int pre = 0, now = 1; dp[0][0] = 1; 15 for(int i = 1; i <= n; i++) { 16 for(int j = 0; j <= sum; j++) dp[now][j] = dp[pre][j]; 17 for(int j = sum; j >= w[i]; j--) 18 if(dp[pre][j-w[i]]) dp[now][j] = 1; 19 for(int j = sum - w[i]; j >= 0; j--) 20 if(dp[pre][j+w[i]]) dp[now][j] = 1; 21 swap(pre, now); 22 } 23 int m; scanf("%d", &m); 24 while(m--) { 25 int x; scanf("%d", &x); 26 if(dp[pre][x]) puts("YES"); 27 else puts("NO"); 28 } 29 } 30 return 0; 31 }