poj1742
题意:有n种物体,每种有ci个,权值为ai,问能组成1到m之间的多少个数
分析:楼教主著名的“男人八题”中的一题,很经典的dp问题,参照《挑战程序设计》上的多重部分和问题,定义bool型的dp[i+1][j],表示前i个数能否得到j,于是就有前i-1个数得到j-k*a[i](0<=k<=c[i]),但是o(n^3),超时了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <bitset> 10 #include <cmath> 11 #include <queue> 12 #include <stack> 13 using namespace std; 14 const int maxn=120; 15 const int maxm=100002; 16 int a[maxn],c[maxn]; 17 bool dp[maxn][maxm]; 18 int n,m; 19 int main() 20 { 21 while(cin>>n>>m) 22 { 23 if(n+m==0) break; 24 for(int i=0;i<n;i++) 25 cin>>a[i]; 26 for(int i=0;i<n;i++) 27 cin>>c[i]; 28 memset(dp,false,sizeof(dp)); 29 dp[0][0]=true; 30 for(int i=0;i<n;i++) 31 { 32 for(int j=0;j<=m;j++) 33 { 34 for(int k=0;k<=c[i]&&k*a[i]<=j;k++) 35 dp[i+1][j]|=dp[i][j-k*a[i]]; 36 } 37 } 38 int cnt=0; 39 for(int i=1;i<=m;i++) 40 if(dp[n][i]) 41 cnt++; 42 cout<<cnt<<endl; 43 } 44 return 0; 45 }
紧接着,参照书上的另外一种解法得到了新的做法,令dp[i+1][j]表示前i个数得到j时第i个数还剩余多少个,于是有了三种情况,(1)若前i-1个已经得到j了,则第i种有c[i]个,(2)若j<a[i]或者dp[i+1][j-a[i]]<=0,则前i个数无法得到j,(3)否则为前i个数得到j-a[i]的个数减1,所以得到如下方程:
- dp[i][j]>=0,dp[i+1][j]=c[i]
- j<a[i]||dp[i+1][j-a[i]]<=0,dp[i+1][j]=-1
- dp[i+1][j]=dp[i+1][j-a[i]]-1
注意这里要用滚动数组,不然内存会爆,总的来说还是一个非常值得学习的题目,orz楼教主
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <bitset> 10 #include <cmath> 11 #include <queue> 12 #include <stack> 13 using namespace std; 14 const int maxn=120; 15 const int maxm=100002; 16 int a[maxn],c[maxn]; 17 int dp[maxm]; 18 int n,m; 19 int main() 20 { 21 while(cin>>n>>m) 22 { 23 if(n+m==0) break; 24 for(int i=0;i<n;i++) 25 scanf("%d",&a[i]); 26 for(int i=0;i<n;i++) 27 scanf("%d",&c[i]); 28 memset(dp,-1,sizeof(dp)); 29 dp[0]=0; 30 for(int i=0;i<n;i++) 31 { 32 for(int j=0;j<=m;j++) 33 { 34 if(dp[j]>=0) 35 dp[j]=c[i]; 36 else if(j<a[i]||dp[j-a[i]]<=0) 37 dp[j]=-1; 38 else 39 dp[j]=dp[j-a[i]]-1; 40 } 41 } 42 int cnt=0; 43 for(int i=1;i<=m;i++) 44 if(dp[i]>=0) 45 cnt++; 46 printf("%d ",cnt); 47 } 48 return 0; 49 }