01背包和完全背包
01背包
每种东西只能放一次
#include<iostream> using namespace std; #define maxn 1001 int dp[maxn]; int volumn[maxn],weight[maxn]; int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>volumn[i]>>weight[i]; } for(int i=1;i<=n;i++)//依次枚举每个物品 { for(int j=m;j>=volumn[i];j--) { dp[j]=max(dp[j],dp[j-volumn[i]]+weight[i]);//判断放还是不放物品价值高 } } // for(int i=0;i<maxn;i++) // cout<<dp[i]<<endl;//dp[i]表示背包容量为i时放东西的最大价值 cout<<dp[m]<<endl;//输出背包容量为m时东西的最大价值 }
测试数据
4 100
100 100
50 60
50 60
30 100
结果
160
变式
Daruk的攻击力上限是W,他可以一次性粉碎重量之和不超过W的任意多个岩石。
假设有N个重量不同的岩石,其中第i个岩石的重量是G[i]。
请问,Daruk一次攻击最多能粉碎的最大重量的岩石是多少?
输入
第一行两个整数,分别代表W和N。
以后N行,每行一个正整数表示G[i]。
输出
一个整数,表示Daruk一次攻击能粉碎的最大岩石重量。
攻击力上限为背包,岩石体积和价值相等
输入样例 1
20 5 7 5 4 18 1
输出样例 1
19
#include<iostream> using namespace std; #define maxn 1001 int dp[maxn]; int volumn[maxn],weight[maxn]; int main() { int n,m; cin>>m>>n; for(int i=1;i<=n;i++) { cin>>volumn[i]; weight[i]=volumn[i]; } for(int i=1;i<=n;i++)//依次枚举每个物品 { for(int j=m;j>=volumn[i];j--) { dp[j]=max(dp[j],dp[j-volumn[i]]+weight[i]);//判断放还是不放物品价值高 } } // for(int i=0;i<maxn;i++) // cout<<dp[i]<<endl;//dp[i]表示背包容量为i时放东西的最大价值 cout<<dp[m]<<endl;//输出背包容量为m时东西的最大价值 }
本题目数字超过
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,half,m,g[50]; unsigned int w,ans,a[(1<<24)+1]; void calc(unsigned int val) { int rest=w-val; int l=1,r=m; while(l<r) { int mid=(l+r+1)/2; if(a[mid]<=rest) l=mid; else r=mid-1; } ans=max(ans,a[l]+val); } void dfs1(int i,unsigned int sum) { if(i==half) { a[++m]=sum; return; } dfs1(i+1,sum); if(sum+g[i]<=w) dfs1(i+1,sum+g[i]); } void dfs2(int i,unsigned int sum) { if(i==n+1) { calc(sum); return; } dfs2(i+1,sum); if(sum+g[i]<=w) dfs2(i+1,sum+g[i]); } int main() { cin>>w>>n; for(int i=1;i<=n;i++) cin>>g[i]; sort(g+1,g+n+1); reverse(g+1,g+n+1); half=n/2+3; dfs1(1,0); sort(a+1,a+m+1); m=unique(a+1,a+m+1)-(a+1); dfs2(half,0); cout<<ans<<endl; }
😵💫
完全背包
每种东西可以放无数次
#include<iostream> using namespace std; const int N=1010; int n,m; int v[N],w[N]; int f[N][N]; int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)//j<=m,设定每个物品最小空间1,即相同的物品最多放入m件 { f[i][j]=f[i-1][j];//加上已经放入的物品价值 if(j>=v[i]) f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);//放入还是不放 } cout<<f[n][m]<<endl; //f[i][m]只考虑前i件物品 //f[n][j]背包最大容量j }
测试数据
4 100
100 100
50 60
50 60
30 100
结果
300