第一题: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 }
第二题: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 }
第三题: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 }
第四题: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 }
多重背包代码:

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 }
第五题: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 }
第六题: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 }
第七题: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 }