有n种不同大小的数字ai,每种各mi个。判断是否可以从这些数字之中选出若干使它们的和恰好为K。
限制条件 1<=n<=100,1<=ai,mi<=100000,1<=K<=100000.
dp[i+1][j]:用前i种数字能否加和成K
为了前i种数字能加和成K,需要能用前i-1种数字加和成j,j-a...j-mi*ai中的某一种
因此dp[i+1][j]=(0<=k<=mi且k*ai<=j时存在使得dp[i][j-k*ai]为真的k)

1 #include<iostream> 2 #include<algorithm> 3 #include<memory.h> 4 #define INF 10000000 5 using namespace std; 6 const int max_n=101; 7 int a[max_n+1]; 8 int m[max_n+1]; 9 int n,r,K; 10 int main() 11 { 12 cin>>n; 13 for(int i=0;i<n;i++) 14 { 15 cin>>a[i]>>m[i]; 16 } 17 cin>>K; 18 bool dp[n+1][K+1]; 19 fill(dp[0],dp[0]+K+1,false); 20 dp[0][0]=true; 21 for(int i=0;i<n;i++) 22 { 23 for(int j=0;j<=K;j++) 24 { 25 for(int k=0;k*a[i]<=j&&k<=m[i];k++) 26 { 27 dp[i+1][j]|=dp[i][j-k*a[i]]; 28 } 29 } 30 } 31 cout<<dp[n][K]<<endl; 32 return 0; 33 }
优化如下
dp[i+1][j]:用前i种数加和得到j时第i种数最多能剩余多少个
dp[i+1][j]=mi (dp[i][j]>=0)
-1 (j<ai||dp[i+1][j-ai]<=0)
dp[i+1][j-ai]-1 (其他)

1 #include<iostream> 2 #include<algorithm> 3 #include<memory.h> 4 #define INF 10000000 5 using namespace std; 6 const int max_n=101; 7 int a[max_n+1]; 8 int m[max_n+1]; 9 int n,r,K; 10 int main() 11 { 12 cin>>n; 13 for(int i=0;i<n;i++) 14 { 15 cin>>a[i]>>m[i]; 16 } 17 cin>>K; 18 int dp[K+1]; 19 memset(dp,-1,sizeof(dp)); 20 dp[0]=0; 21 for(int i=0;i<n;i++) 22 { 23 for(int j=0;j<=K;j++) 24 { 25 if(dp[j]>=0) 26 { 27 dp[j]=m[i]; 28 } 29 else if(j<a[i]||dp[j-a[i]]<=0) 30 { 31 dp[j]=-1; 32 } 33 else 34 { 35 dp[j]=dp[j-a[i]]-1; 36 } 37 } 38 } 39 cout<<dp[K]<<endl; 40 return 0; 41 }