基础背包
Posted zjl192628928
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础背包相关的知识,希望对你有一定的参考价值。
hdu 3033 分组背包
题目大意:总共有n双鞋,每个鞋子有个牌子,有k种牌子,每种牌子至少买一双鞋子。每双鞋子有一定的消费跟价值。求用m多的钱买最多价值的鞋。
解题思路:这题和分组背包有点不一样,从每组至多一个变成了每组至少一个,多加个if语句就可以了
#include<iostream> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int maxn=10005; int N,V,M,K,dp[20][maxn],value[maxn],num[maxn],weight[maxn]; struct node{ int cost,val; node(int a,int b){ cost=a; val=b; } }; int main(){ while(cin>>N>>M>>K){ for(int i=1;i<=20;i++)vec[i].clear(); memset(dp,-1,sizeof(dp)); for(int i=0;i<=M;i++)dp[0][i]=0; for(int i=1;i<=N;i++){ int x,y,z; cin>>x>>y>>z; vec[x].push_back(node(y,z)); } for(int i=1;i<=K;i++){ for(int j=0;j<vec[i].size();j++){ for(int k=M;k>=vec[i][j].cost;k--){ if(dp[i][k-vec[i][j].cost]!=-1) //非第一次取第i组 dp[i][k]=max(dp[i][k],dp[i][k-vec[i][j].cost]+vec[i][j].val); if(dp[i-1][k-vec[i][j].cost]!=-1) //第一次取第i组 dp[i][k]=max(dp[i][k],dp[i-1][k-vec[i][j].cost]+vec[i][j].val); //不能调换两个if的顺序因为如果第一个在上面则两个都会执行,重复计算 } } } if(dp[K][M]<0)puts("Impossible"); else cout<<dp[K][M]<<endl; } return 0; }
hdu 2191 多重背包
Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
解题思路:多重背包,无坑
#include<iostream> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int maxn=10005; int n,V,M,K,dp[maxn],value[maxn],num[maxn],weight[maxn]; int main(){ int T; cin>>T; while(T--){ cin>>V>>n; for(int i=1;i<=n;i++) cin>>weight[i]>>value[i]>>num[i]; memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ if(weight[i]*num[i]>V){ for(int j=weight[i];j<=V;j++) dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); }else{ for(int j=1;j<=num[i];j*=2){ for(int k=V;k>=j*weight[i];k--) dp[k]=max(dp[k],dp[k-j*weight[i]]+j*value[i]); num[i]-=j; } if(num[i]){ for(int k=V;k>=num[i]*weight[i];k--) dp[k]=max(dp[k],dp[k-num[i]*weight[i]]+num[i]*value[i]); } } } cout<<dp[V]<<endl; } return 0; }
hdu 3721 多重背包
我们都知道英语是非常重要的,所以阿惠努力做到这一点,以便学习更多的英语单词。为了知道这个词有它的价值和书写的复杂性(每个词的长度不超过10个,只用小写字母),阿辉写下的复杂度总和小于或等于C问题:ahui可以得到的最大值。注意:输入的单词将不相同
输入
每个测试用例的第一行是两个整数n,c,表示ahui的单词数和所写单词的总复杂性。(1≤N≤100000,1≤C≤10000)
接下来的n行中的每一行都是一个字符串和两个整数,表示单词、值(vi)和复杂性(ci)。(0≤vi,Ci≤10)
产量
为每个测试用例在一行中输出最大值。
解题思路:由于N的范围很大,所以我们用01背包去做肯定是会超时的,再看vi和ci都很像最大为10,我们把vi和ci都相同的看成同一个单词,最多就121种,计算每种的数量,再跑多重背包就可以了。
#include<iostream> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int maxn=100005; int n,V,M,K,dp[maxn],value[maxn],num[15][15],weight[maxn]; int main(){ while(~scanf("%d%d",&n,&V)){ memset(num,0,sizeof(num)); int sum=0; for(int i=1;i<=n;i++){ char s[105]; getchar(); int x,y; scanf("%s %d %d",s,&x,&y); if(num[x][y]==0){ sum++; value[sum]=x; weight[sum]=y; num[x][y]++; //cout<<x<<" "<<y<<" "<<num[x][y]<<endl; }else num[x][y]++; } n=sum; memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ //cout<<value[i]<<" "<<weight[i]<<" "<<num[value[i]][weight[i]]<<endl; if(num[value[i]][weight[i]]*weight[i]>V){ for(int j=weight[i];j<=V;j++) dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); }else{ for(int j=1;j<=num[value[i]][weight[i]];j*=2){ for(int k=V;k>=j*weight[i];k--) dp[k]=max(dp[k],dp[k-j*weight[i]]+j*value[i]); num[value[i]][weight[i]]-=j; } if(num[value[i]][weight[i]]){ int cnt=num[value[i]][weight[i]]; for(int k=V;k>=cnt*weight[i];k--) dp[k]=max(dp[k],dp[k-cnt*weight[i]]+cnt*value[i]); } } } printf("%d ",dp[V]); } return 0; }
hdu 1712 分组背包
Acboy这个学期有n门课程,他计划最多花m天学习。当然,他将从不同的课程中获得的利润取决于他花在这门课程上的天数。如何安排m天学习n门课程,以使利润最大化?
输入
输入由多个数据集组成。一个数据集以包含两个正整数n和m的一行开始,n是课程数,m是acboy的天数。
接下来,按照矩阵a[i][j],(1<=i<=n<=100,1<=j<=m<=100)。a[i][j]表示如果acboy在课程上花费j天,他将获得价值a[i][j]的利润。
n=0,m=0结束输入。
产量
对于每个数据集,程序应该输出一行,其中包含acboy将获得的最大利润数。
解题思路:分组背包模板
#include<iostream> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int maxn=100005; int n,V,m,K,dp[maxn],value[105][105],num[15][15],weight[maxn]; int main(){ while(cin>>n>>m){ if(n+m==0)break; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>value[i][j]; memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) for(int k=m;k>=1;k--) //注意第二个循环和第三个循环不可调换顺序 for(int j=1;j<=m;j++) if(k-j>=0) dp[k]=max(dp[k],dp[k-j]+value[i][j]); cout<<dp[m]<<endl; } return 0; }
hdu 2955 01背包
题目大意:给出抢劫n个银行所能得到的价值及风险,问风险在p以内可抢劫的最大价值
解题思路: 由于被抓的概率都为浮点数,不可作为背包的容量,所以我们只能用价值来做背包的容量,还有一个点就是,我们很难求被抓的概率,所以我们转化成求他不被抓的概率,我们计算它最后的逃跑概率是否大于1-p的最大值即为答案。
#include<iostream> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long ll; const int maxn=100005; int n,m,V,K,value[maxn],num[15][15]; double p,weight[maxn],dp[maxn]; int main(){ int T; cin>>T; while(T--){ cin>>p>>n; V=0; for(int i=1;i<=n;i++){ cin>>value[i]>>weight[i]; V+=value[i]; } memset(dp,0,sizeof(dp)); dp[0]=1; //抢劫0元逃跑的概率为1 for(int i=1;i<=n;i++) for(int j=V;j>=value[i];j--) dp[j]=max(dp[j],dp[j-value[i]]*(1-weight[i])); for(int i=V;i>=0;i--){ if(dp[i]>=1-p){ cout<<i<<endl; break; } } } return 0; }
以上是关于基础背包的主要内容,如果未能解决你的问题,请参考以下文章