基础背包(三)
hdu 2159 二维完全背包
Input
输入数据有多组,对于每组数据第一行输入n,m,k,s(0 < n,m,k,s < 100)四个正整数。分别表示还需的经验值,保留的忍耐度,怪的种数和最多的杀怪数。接下来输入k行数据。每行数据输入两个正整数a,b(0 < a,b < 20);分别表示杀掉一只这种怪xhd会得到的经验值和会减掉的忍耐度。(每种怪都有无数个)
Output
输出升完这级还能保留的最大忍耐度,如果无法升完这级输出-1。
解题思路:dp[i][k]表示在消耗i忍耐度下杀k只怪得到的最多经验值
多加一层循环就可以了,注意完全背包的顺序为顺序
#include<iostream> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int maxn=100005; int n,V,m,K,s,dp[105][105],value[105],num[15][15],weight[maxn]; int main(){ while(cin>>n>>m>>K>>s){ memset(dp,0,sizeof(dp));//dp[i][k]表示在消耗i忍耐度下杀k只怪得到的最多经验值 for(int i=1;i<=K;i++) cin>>value[i]>>weight[i]; for(int i=1;i<=m;i++) for(int j=1;j<=K;j++) for(int k=1;k<=s;k++) if(i>=weight[j])dp[i][k]=max(dp[i][k],dp[i-weight[j]][k-1]+value[j]); int flag=0; for(int i=1;i<=m;i++) if(dp[i][s]>=n){ //dp[i][s]为在消耗i忍耐度下获得经验的最大值 cout<<m-i<<endl; flag=1; break; } if(!flag)puts("-1"); } return 0; }
hdu 3496 二维01背包
题目大意:有N个碟片,你只能选择M个进行播放,最多能观看L分钟。给出每个碟片的播放时间和看完后能收获的快乐值,问能否看完这M个碟片,如果能全部看完的话,输出最大快乐值,如果不能看完输出0
解题思路:dp[i][k]表示用k分钟观看i个影片所能获得的最大价值,注意初始化,当i=0时,合法且结果为0,其他情况初始化为负数。最后判断下结果是否为负,则可判断是否可看完
#include<iostream> #include<cstring> #include<vector> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int maxn=3100000; int n,V,m,l,K,s,value[105],Time[105],dp[105][1005]; int main(){ int T; cin>>T; while(T--){ cin>>n>>m>>l; for(int i=1;i<=n;i++) cin>>Time[i]>>value[i]; for(int i=0;i<=m;i++) for(int j=0;j<=l;j++){ if(i)dp[i][j]=-0x3f3f3f3f; else dp[i][j]=0; } for(int i=1;i<=n;i++) for(int j=m;j>=1;j--) for(int k=l;k>=Time[i];k--) dp[j][k]=max(dp[j][k],dp[j-1][k-Time[i]]+value[i]); if(dp[m][l]>=0)cout<<dp[m][l]<<endl; else puts("0"); } return 0; }
hdu 2546 01背包
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
Input多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。
Output对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
解题思路:我们考虑用最后5元钱买最贵的菜,这样就可以使卡上的余额最少了,所以我们可以先拿开这5块钱,用剩下的m-5块钱买其他的n-1道菜所能买的最大值,即可以用01背包,体积为m-5。
#include<iostream> #include<cstring> #include<vector> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int maxn=100005; int n,V,m,K,s,dp[maxn],value[maxn],num[15][15],weight[maxn]; int main(){ while(cin>>n&&n){ for(int i=1;i<=n;i++) cin>>value[i]; sort(value+1,value+1+n); cin>>m; if(m<5){ cout<<m<<endl; continue; } m-=5; memset(dp,0,sizeof(dp)); for(int i=1;i<n;i++) for(int j=m;j>=value[i];j--) dp[j]=max(dp[j],dp[j-value[i]]+value[i]); cout<<m-dp[m]+5-value[n]<<endl; } return 0; }
hdu 3466 排序+01背包
题目大意:有n个物品,每个物品有一个价格,一个价值,还有一个最低金额限制,即如果你的钱低于这个金额,不可购买此物品,问m块钱可以买到的最大价值。
解题思路:虽然可以看出这是一个01背包,但是又不同于01背包,当最低限制金额低于物品的价格时可以看成是01背包,但是高于物品的价格便不一样了,还没怎么弄明白。。。
#include<iostream> #include<cstring> #include<vector> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1000005; int n,m,dp[maxn]; struct node{ int cost,value,q; bool operator<(node x){ return q-cost<x.q-x.cost; } }p[maxn]; int main(){ while(cin>>n>>m){ memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) cin>>p[i].cost>>p[i].q>>p[i].value; sort(p+1,p+n+1); for(int i=1;i<=n;i++) for(int j=m;j>=p[i].q;j--){ dp[j]=max(dp[j],dp[j-p[i].cost]+p[i].value); } cout<<dp[m]<<endl; } return 0; }
hdu 1864 01背包
Input
测试输入包含若干测试用例。每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(<=30)是发票张数。随后是 N 行输入,每行的格式为:
m Type_1:price_1 Type_2:price_2 ... Type_m:price_m
其中正整数 m 是这张发票上所开物品的件数,Type_i 和 price_i 是第 i 项物品的种类和价值。物品种类用一个大写英文字母表示。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例输出1行,即可以报销的最大数额,精确到小数点后2位。
解题思路:由于报销额为double类型,而结果是保留两位小数,那我们可以直接把报销额放大100倍,并且转化成整型,然后跑01背包,最后结果除以100就可以了。
#include<iostream> #include<cstring> #include<vector> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int maxn=3100000; int n,V,m,K,s,value[maxn],dp[maxn]; double v; int main(){ while(cin>>v>>n&&n){ int sum=0; memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ cin>>m; double x,res1=0,res2=0,res3=0;; char c,d; int flag=0; for(int j=1;j<=m;j++){ cin>>c>>d>>x; if(flag){ continue; }else{ if(c=='A')res1+=x; else if(c=='B')res2+=x; else if(c=='C') res3+=x; else flag=1; } } if(res1>600||res2>600||res3>600||res1+res2+res3>1000)flag=1; if(!flag)value[++sum]=(int)((res1+res2+res3)*100); } n=sum; V=(int)(v*100); for(int i=1;i<=n;i++) for(int j=V;j>=value[i];j--) dp[j]=max(dp[j],dp[j-value[i]]+value[i]); printf("%.2lf\n",dp[V]/100.0); } return 0; }