4月21日

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 }
TLE

紧接着,参照书上的另外一种解法得到了新的做法,令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\n",cnt);
47     }
48     return 0;
49 }
Accept

 

posted @ 2016-04-21 21:45  wolf940509  阅读(420)  评论(0编辑  收藏  举报