zoukankan      html  css  js  c++  java
  • 完全背包专题

    第一题: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,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
  • 相关阅读:
    服务器SSL不安全漏洞修复方案
    vs2010 vs2013等vs中如何统计整个项目的代码行数
    Windows10中的IIS10.0安装php manager和IIS URL 重写2.0组件的方法
    让Windows Server 2008r2 IIS7.5 ASP.NET 支持10万并发请求
    angularJS 上传multipart/form-data
    idea 取消缩进
    Java 自动检测文本文件编码
    idea 快捷键
    java 8 bug
    Python学习笔记
  • 原文地址:https://www.cnblogs.com/xiaowuga/p/7428981.html
Copyright © 2011-2022 走看看