就类似完全背包。。不过要恰好等于背包容量。。
就是给n种数ai,各mi个,判断是否能从这些数字中选出若干个使他们的和为v。
用dp求解,dp[i+1][j]表示前i种数字能否加和得到j。dp[i+1][j] 只要dp[i][j-k*ai]有一个为真那么就为真。(0<=k<=mi)
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 109 int a[M],m[M]; bool dp[M][100009]; int main() { int n; while(scanf("%d",&n)==1) { memset(dp,false,sizeof(dp)); for(int i = 0;i < n;i++) scanf("%d",&a[i]); for(int i = 0;i < n;i++) scanf("%d",&m[i]); int v; scanf("%d",&v); dp[0][0] = true; for(int i = 0;i < n;i++) { for(int j = 0;j <= v;j++) for(int k = 0;k<=m[i]&&k*a[i]<=j;k++) { dp[i+1][j] |= dp[i][j-k*a[i]]; } } if(dp[n][v]) printf("YES\n"); else printf("NO\n"); } return 0; }
书上说用dp数组只用来求bool结果,会造成浪费。给出了一个优化,dp[i+1][j]表示前i种数字中加和为j后还剩下几个第i种数字(如果不能加和为J 就为-1)
当dp[i][j]>=0时,dp[i+1][j] = mi 当dp[i+1][j-ai]<=0或者j<ai(防止数组下标变为负数)时 dp[i+1][j] = -1 其他情况下,dp[i+1][j] = dp[i+1][j-ai]-1
给出代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 109 int a[M],m[M]; int dp[M][100009]; int main() { int n; while(scanf("%d",&n)==1) { memset(dp,-1,sizeof(dp)); for(int i = 0;i < n;i++) scanf("%d",&a[i]); for(int i = 0;i < n;i++) scanf("%d",&m[i]); int v; scanf("%d",&v); dp[0][0] = 0; for(int i = 0;i < n;i++) for(int j = 0;j <= v;j++) { if(dp[i][j]>=0) dp[i+1][j] = m[i]; else if(j<a[i] || dp[i+1][j-a[i]]<=0) dp[i+1][j] = -1;//一定注意要防止数组下标变为0 else dp[i+1][j] = dp[i+1][j-a[i]]-1; } if(dp[n][v]>=0) printf("YES\n"); else printf("NO\n"); } return 0; }优化成一维:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 109 int a[M],m[M]; int dp[100009]; int main() { int n; while(scanf("%d",&n)==1) { memset(dp,-1,sizeof(dp)); for(int i = 0;i < n;i++) scanf("%d",&a[i]); for(int i = 0;i < n;i++) scanf("%d",&m[i]); int v; scanf("%d",&v); dp[0] = 0; for(int i = 0;i < n;i++) for(int j = 0;j <= v;j++) { if(dp[j]>=0) dp[j] = m[i]; else if(j<a[i] || dp[j-a[i]]<=0) dp[j] = -1;//一定注意要防止数组下标变为0 else dp[j] = dp[j-a[i]]-1; } if(dp[v]>=0) printf("YES\n"); else printf("NO\n"); } return 0; }