完全背包专题

第一题:UVA674 Coin Change

题目链接:https://vjudge.net/problem/UVA-674

题目意思:意思太简单了,不借解释了,最简单的完全背包问题,总共就四个物品

代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=10000; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 II dp[N];
25 II w[5]={1,5,10,25,50};
26 II n;
27 int main() {
28     ios::sync_with_stdio(false);cin.tie(0);
29     while(cin>>n){
30         mem(dp,0);
31         dp[0]=1;
32         for(II i=0;i<5;i++){
33             for(II j=w[i];j<=n;j++){
34                dp[j]+=dp[j-w[i]];
35             }
36         }
37         cout<<dp[n]<<endl;
38         
39     }
40     return 0;
41 }
View Code

第二题:UVA147 Dollars

题目链接:https://vjudge.net/problem/UVA-147

题目意思:上一题的加强版,而且是浮点数输入,做法是浮点数转成整数(转换的时候注意四舍五入),然后完全背包,唯一的坑点是输出格式有点坑。

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=100000; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 double eps=1e-8;
25 II w[11]={10000,5000,2000,1000,500,100,200,50,20,10,5};
26 LL dp[30000+10]={0};
27 int main() {
28     ios::sync_with_stdio(false);cin.tie(0);
29     double n;
30     dp[0]=1;
31     for(II i=0;i<11;i++)
32         for(II j=w[i];j<=30000;j++)
33             dp[j]+=dp[j-w[i]];
34     while(cin>>n){
35          if((n-0)<=eps) break;
36          II t=(int)(n*100+0.5);
37          printf("%6.2lf%17lld\n",n,dp[t]);
38     }
39     return 0;
40 }
View Code

第三题:poj3181 Dollar Dayz

题目链接:http://poj.org/problem?id=3181

题目意思:输入n,和k,问将n用1到k这k个数字进行拆分,有多少种拆分方法。例如:n=5,k=3 则有n=3+2,n=3+1+1,n=2+1+1+1,n=2+2+1,n=1+1+1+1+1这5种拆分方法。

思路:很明显的的一个完全背包,但是这道题是一个大数题,又没有给模数,但是直接套一个大数模板是会超时的,这里介绍一个巧妙的方法,就是把一个数分成两个部分,对于大于10^18的部分存在一个数中,小于10^18的部分存在一个数里面。

代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=100000; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 LL a[1001];
25 LL b[1001];
26 LL mod=1;
27 int main() {
28     II n,k;
29     for(II i=0;i<18;i++) mod*=10; 
30     while(cin>>n>>k){
31         mem(a,0);mem(b,0);
32         b[0]=1;
33         for(II i=1;i<=k;i++)
34             for(II j=i;j<=n;j++){
35                 a[j]=a[j]+a[j-i]+(b[j-i]+b[j])/mod;
36                 b[j]=(b[j]+b[j-i])%mod;
37             }
38         if(a[n]) cout<<a[n];
39         cout<<b[n]<<endl;
40     } 
41     return 0;
42 }
View Code

第四题:poj1787 Charlie's Change

题目链接:http://poj.org/problem?id=1787

题目意思:有四种硬币,1分,5分,10分,25分,分别有a,b,c,d种,给出一个n分钱,要求你求出组成n分钱最多需要的硬币数量,并且输出组成它的各种硬币的数量。

题目思路:这个题目明显是一个多重背包记录路径的题目,但是网络上似乎有完全背包的做法。这里我两种做法都写了。但是注意不管对于哪一种做法,这个背包问题是要求 满包处理的。所以转移的时候需要判断该状态是否已经存在。

对于完全背包的做法:

用了一个used数组来表示在某个状态下,使用某种硬币的的数量,来维护使用的数量不超过限制,对满足限制条件的才能转移,这里对于记录路径的数组,是一维的,这里注意这种的方法的使用,是有限制条件的,只有在满足满包的情况下才能使用。

对于多重背包的做法:

就是一个多重背包的模板题,和打印路径的模板。

完全背包代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=10000+100; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 II V,C[4]={1,5,10,25},n[4];
25 II dp[N];
26 II used[N];
27 II path[N];
28 int main() {
29     ios::sync_with_stdio(false);cin.tie(0);
30     while(cin>>V>>n[0]>>n[1]>>n[2]>>n[3]){
31         if(V==0&&n[0]==0&&n[1]==0&&n[2]==0&&n[3]==0) break;
32         mem(dp,-1);
33         mem(path,0);
34         dp[0]=0;
35         path[0]=-1;
36         for(II i=0;i<4;i++){
37             mem(used,0);
38             for(II j=C[i];j<=V;j++){
39                 if(dp[j-C[i]]+1>dp[j]&&dp[j-C[i]]>=0&&used[j-C[i]]<n[i]){
40                     dp[j]=dp[j-C[i]]+1;
41                     used[j]=used[j-C[i]]+1;
42                     path[j]=j-C[i];
43                 }
44             }
45         }
46         II ans[N]; 
47         mem(ans,0);
48         if(dp[V]<0){
49             cout<<"Charlie cannot buy coffee."<<endl;
50         }
51         else{
52             while(path[V]!=-1){
53                 ans[V-path[V]]++;
54                 V=path[V];
55             }
56            cout<<"Throw in "<<ans[1]<<" cents, "<<ans[5]<<" nickels, "<<ans[10]<<" dimes, and "<<ans[25]<<" quarters."<<endl;
57             
58         }
59     }
60     return 0;
61 }
View Code

多重背包代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=10000+100;
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 II dp[N];
25 II val[N];
26 II path[4][N][2];
27 II C[4]={1,5,10,25};
28 II n[4];
29 II V;
30 II ans[4];
31 void zero_one_pack(II p,II k){
32    for(II i=V;i>=k*C[p];i--){
33         if(dp[i-k*C[p]]+k>dp[i]&&dp[i-k*C[p]]!=-1){
34             dp[i]=dp[i-k*C[p]]+k;
35             path[p][i][0]=1;
36             path[p][i][1]=k;
37         }
38    } 
39 }
40 void comleple_pack(II p){
41    for(II i=C[p];i<=V;i++){
42         if(dp[i-C[p]]+1>dp[i]&&dp[i-C[p]]!=-1){
43             dp[i]=dp[i-C[p]]+1;
44             path[p][i][0]=1;
45             path[p][i][1]=1;   
46         }
47    }
48 }
49 
50 void multiple_pack(){
51     mem(dp,-1);
52     mem(path,0);
53     dp[0]=0;
54     for(II i=0;i<4;i++){
55         if(n[i]*C[i]>=V) comleple_pack(i);
56         else{
57             II ct=n[i];
58             for(II j=1;j<=ct;j*=2){
59                 zero_one_pack(i,j);
60                 ct-=j;
61             }
62             if(ct) zero_one_pack(i,ct);
63         }
64     }
65 }
66 int main() {
67     ios::sync_with_stdio(false);cin.tie(0);
68     while(cin>>V>>n[0]>>n[1]>>n[2]>>n[3]){
69         if(V==0&&n[0]==0&&n[1]==0&&n[2]==0&&n[3]==0) break;
70         mem(ans,0);
71         multiple_pack(); 
72         if(dp[V]!=-1){
73            II i=3,j=V;
74            while(i>=0&&j){
75                 if(path[i][j][0]){
76                     ans[i]+=path[i][j][1];
77                     j-=path[i][j][1]*C[i];
78                 }
79                 else i--;
80            } 
81            cout<<"Throw in "<<ans[0]<<" cents, "<<ans[1]<<" nickels, "<<ans[2]<<" dimes, and "<<ans[3]<<" quarters."<<endl;
82         }
83         else cout<<"Charlie cannot buy coffee."<<endl;
84     }
85     return 0;
86 }
View Code

第五题:poj3260  The Fewest Coins

题目链接:http://poj.org/problem?id=3260

题目意思:说有一个人去买m元的东西,有n种钱币,每种钱币的面额是w[i],个数是C[i],售货员每种钱币有无数多个。现在这个人想让交易的钱个数最少,即找回的和付出钱的张数最少。

思路:真的是没想懂,这个上界是怎么判断。其实可以二分xjb试上界,一开始开大一点,其实最多wa两发就可以过,我们找一个 ans=min(ans,g[i]+f[i+P]),P是价格,i是找回的钱。

买家:多重背包;

售货员:完全背包;

开两个数组,分别计算出买家,售货员凑出面额的最少张数,这里注意是凑出这个面额,说明这里需要满包处理,这里上界的处理证明可以百度看一下别人的博客。

代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=120*120+15000; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 II n,P,MX;
25 II V[110],C[110];
26 II f[N],g[N];
27 void complepack(II dp[],II sum,II pos){
28     for(II i=V[pos];i<=sum;i++){
29         dp[i]=min(dp[i-V[pos]]+1,dp[i]);
30     }
31 }
32 void zero_one_pack(II sum,II pos,II k){
33     II t=k*V[pos];
34     for(II i=sum;i>=t;i--){
35         f[i]=min(f[i-t]+k,f[i]); 
36     }
37 }
38 void multiplepack(){
39     mem(f,inf);
40     f[0]=0;
41     II sum=MX*MX+P+1;
42     for(II i=0;i<n;i++){
43         if(C[i]*V[i]>=sum){
44             complepack(f,sum,i);
45         }
46         else{
47             II ct=C[i];
48             for(II j=1;j<=ct;j*=2){
49                 zero_one_pack(sum,i,j);
50                 ct-=j;
51             }
52             if(ct) zero_one_pack(sum,i,ct);
53         }
54     }
55 }
56 int main() {
57     ios::sync_with_stdio(false);cin.tie(0);
58     while(cin>>n>>P){
59         MX=-1;
60         for(II i=0;i<n;i++) {cin>>V[i];MX=max(MX,V[i]);}
61         for(II i=0;i<n;i++) cin>>C[i];
62         multiplepack();
63         mem(g,inf);
64         g[0]=0;
65         for(II i=0;i<n;i++)
66             complepack(g,MX*MX+1,i);
67         II ans=inf;
68         II t=MX*MX+1;
69         for(II i=0;i<=t;i++){
70             if(g[i]+f[i+P]<ans){
71                 ans=g[i]+f[i+P];
72             }
73         }
74         if(ans==inf){
75             cout<<-1<<endl;
76         }
77         else cout<<ans<<endl;
78     } 
79     return 0;
80 }
View Code

第六题:poj2063 Investment

题目链接:http://poj.org/problem?id=2063

题目意思:求投资k年获得最大投资,每年都选最大利息的方案进行投资k年后就可以得到最多的人民币。

题目思路:背包最大容量不断改变的完全背包,多加一维循环代表年份。

代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=100000; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 II dp[100000+10],S,year,d;
25 II w[15],v[N];
26 int main() {
27     ios::sync_with_stdio(false);cin.tie(0);
28     II T;
29     cin>>T;
30     while(T--){
31         cin>>S>>year>>d;
32         for(II i=0;i<d;i++) {cin>>w[i]>>v[i];w[i]/=1000;}
33         II ans;
34         for(II i=1;i<=year;i++){
35             II ts=S/1000;
36             mem(dp,0);
37             for(II j=0;j<d;j++)
38                 for(II k=w[j];k<=ts;k++){
39                     dp[k]=max(dp[k-w[j]]+v[j],dp[k]);
40                 }
41             S=S+dp[ts];
42             ans=S;
43         }
44         cout<<ans<<endl;
45     }
46     return 0;
47 }
View Code

第七题:zoj3623 Battle Ships

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3623

题目意思:对方有L滴血,我们有n种船可以选择,每种船建造时间为t,建好后每秒对敌方造成l点伤害,问最少多少时间能干掉对方。

题目思路:考虑时间倒流。我们假设x秒可以干倒对方,这样第x秒就是第0秒,战舰完成的时间就是x-w[i]秒,攻击的时间就是x-w[i]秒,有点小难理解,我也是想了一段时间才明白,这个想法确实十分巧妙。

代码:

 1 //Author: xiaowuga
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <set>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <cstdio>
10 #include <ctime>
11 #include <map>
12 #include <bitset>
13 #include <cctype>
14 #define maxx INT_MAX
15 #define minn INT_MIN
16 #define inf 0x3f3f3f3f
17 #define mem(s,ch) memset(s,ch,sizeof(s))
18 #define nc cout<<"nc"<<endl
19 #define sp " "
20 const long long N=33; 
21 using namespace std;
22 typedef long long LL;
23 typedef int II;
24 II n,L;
25 II w[N],v[N];
26 II dp[350];
27 int main() {
28     ios::sync_with_stdio(false);cin.tie(0);
29     while(cin>>n>>L){
30         for(II i=0;i<n;i++) cin>>w[i]>>v[i];
31         mem(dp,0);
32         for(II i=0;i<n;i++){
33             for(II j=w[i];j<=330;j++)
34                 dp[j]=max(dp[j],dp[j-w[i]]+(j-w[i])*v[i]);
35         }
36         for(II i=0;i<=330;i++){
37             if(dp[i]>=L){
38                 cout<<i<<endl; break;
39             }
40         }
41     } 
42     return 0;
43 }
View Code

 

posted on 2017-08-25 17:21  xiaowuga  阅读(238)  评论(0)    收藏  举报

导航