九背包问题
https://www.kancloud.cn/kancloud/pack/70125
https://www.cnblogs.com/Yeasio-Nein/p/bagpack.html
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f [ i ] [ v ] = m a x f [ i − 1 ] [ v ] , f [ i − 1 ] [ v − c [ i ] ] + w [ i ] f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} f[i][v]=maxf[i−1][v],f[i−1][v−c[i]]+w[i]
//无优化模板
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
f[i][c]=f[i-1][c];
if(c>=w[i])
f[i][c]=max(f[i][c],f[i-1][c-w[i]]+v[i]);
}
}
//一维数组优化
for(int i=1;i<=n;i++)
{
for(int c=m;c>=0;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
//常数优化
for(int i=1;i<=n;i++)
{
sumw+=w[i];
bound=max(m-sumw,w[i]);
for(int c=m;c>=bound;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
01背包例题;典型的01背包
hdoj2602:Bone Collector
#include
#include
#incldue
#include
#include
#define ll long long int
#define maxn 1005
using namespace std;
int v[maxn],w[maxn],dp[maxn];
int main()
{
int t,n,V,i,j,ans;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
scanf("%d %d",&n,&v);
for(i=0;i<n;i++)
scanf("%d",&v[i]);
for(i=0;i<n;i++)
scanf("%d",&w[i]);
for(i=0;i<n;i++)
for(j=V;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[v]);
}
return 0;
}
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本思路
这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:
f [ i ] [ v ] = m a x f [ i − 1 ] [ v − k ∗ c [ i ] ] + k ∗ w [ i ] ∣ 0 < = k ∗ c [ j ] < = v f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[j]<=v} f[i][v]=maxf[i−1][v−k∗c[i]]+k∗w[i]∣0<=k∗c[j]<=v
或者
f [ i ] [ v ] = m a x f [ i − 1 ] [ v ] , f [ i ] [ v − c [ i ] ] + w [ i ] f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]} f[i][v]=maxf[i−1][v],f[i][v−c[i]]+w[i]
//完全背包
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
1. HDU- 1114 - Piggy-Bank
题意: 一个存钱罐,给你一开始体积和总共可以装的体积,然后在给你n 个硬币,给你相应的价值和体积,问你装满的话最少可以装多少钱,硬币可以用无限次
分析: 一个完全背包的板子题,直接看代码。
#include
using namespace std;
const int N=le5+10,INF=0x3f3f3f3f;
int V[N],W[N],dp[N],s,e;
ios_base::sync_with_stdio(0);
int T;
cin>>T;
while(T--)
{
int n;
cin>>s>>e>>n;
for(int i=0;i<N;i++)
dp[i]=INF;
dp[0]=0;
for(int i=0;i<n;i++)
{
cin>>V[i]>>W[i];
}
for(int i=0;i<n;i++)
{
for(int j=w[i];j<=e-s;j++){
dp[j]=min(dp[j],dp[j-w[i]+v[i]]);
}
if(dp[e-s]==INF) puts("This is imposssible");
else
printf("The minimum amount of money in the piggy-bank is%d",dp[e-s]);
}
return 0;
}
HDU - 1248 - 寒冰王座
题意:只给你一个N元的钞票,让你求你最少浪费多少钱,你可以买三样东西价格分别为150,200,350,每个可以买无限次
分析:这个也是比较正的板子题,直接看代码
#include
using namespace std;
const int N=le5+10,INF=0x3f3f3f3f;
int dp[N],a[5];
int main()
{
ios_base::sync_with_stdio(0);
int T;
cin>>T;
a[0]=150;
a[1]=200;
a[2]=350;
while(T--)
{
int n;
cin>>n;
for(int i=0;i<N;i++)
dp[i]=0;
for(int i=0;i<3;i++)
{
for(int j=a[i];j<=n;j++)
{
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
cout<<n-dp[n]<<endl;
}
return 0;
}
有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大
这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则有状态转移方程:
f [ i ] [ v ] = m a x f [ i − 1 ] [ v − k ∗ c [ i ] ] + k ∗ w [ i ] ∣ 0 < = k ∗ w [ i ] < = n [ i ] f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*w[i]<=n[i]} f[i][v]=maxf[i−1][v−k∗c[i]]+k∗w[i]∣0<=k∗w[i]<=n[i]
const int maxn=100005;
int w[amxn],v[maxn],num[maxn];//w:重量 v:价值 num:数量 // w: weight, //v:value, num:number
int dp[maxn];
int V;//背包容量
//01背包
void ZeroOnePack(int w,int v)
{
for(int j=v;j>=w;j--)
{
dp[j]=max(dp[j],dp[j-w]+v);
}
}
//完全背包
void CompletePack(int w,int v)
{
for(int j=w;j<=v;j++)
{
dp[j]=max(dp[j],dp[j-w]+v);
}
}
//多重背包
void MultiplePack(int w,int v,int num)
{
if(w*num>=V)
{
CompletePack(w,v);
}
else
{
int k=1;
while(k<num)
{
ZeroOnePack(k*w,k*v);
num-=k;
k<<=1;
}
ZeroOnePack(num*w,num*v);
}
}
//多重背包
for(int i=1;i<=n;i++)
{
if(w[i]*a[i]>m)
{
for(int c=0;c<=m;c++)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
else
{
k=1;
amount=a[i];
while(k<amount)
{
for(int c=k*w[i];c>=0;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+k*v[i]);
}
amount-=k;
k<<=1;
}
for(int c=amount*w[i];c>=0;c--)
{
f[c]=max(f[c],f[c-w[i]]+amount*v[i]);
}
}
}
如果将P01、P02、P03混合起来。也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。应该怎么求解呢?
for i=1…N
if 第i件物品属于01背包
for v=V…0
f[v]=max{f[v],f[v-c[i]]+w[i]};
else if 第i件物品属于完全背包
for v=0…V
f[v]=max{f[v],f[v-c[i]]+w[i]};
for i=1…N
if 第i件物品属于01背包
ZeroOnePack(c[i],w[i])
else if 第i件物品属于完全背包
CompletePack(c[i],w[i])
else if 第i件物品属于多重背包
MultiplePack(c[i],w[i],n[i])
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
【题目描述】Description
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?
【输入描述】 Input Description
第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限
【输出描述】 Output Description
1个数Ans表示所装物品价值的最大值
【样例输入】 Sample Input
2 10
3 7 2
2 4 -1
【样例输出】 Sample Output
22
【数据范围及提示】 Data Size & Hint
对于100%的数据,V <= 200000 , N <= 200
https://www.cnblogs.com/xiaoningmeng/p/6068741.html
#include
#include
#include
using namespace std;
int V,n;
int w[210],v[210],m[210];
int f[200010];
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&w[i],&v[i],&m[i]);
for(int i=1;i<=n;i++)
{
if(m[i]==-1)//完全背包
for(int j=w[i];j<=V;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
else//01与多重背包
{
int x=m[i];
for(int k=1;k<=x;k<<=1)
{
for(int j=V;j>=w[i]*k;j--)
f[j]=max(f[j],f[j-w[i]*k]+v[i]*k);
x-=k;
}
if(x)
for(int j=V;j>=w[i]*x;j--)
f[j]=max(f[j],f[j-w[i]*x]+v[i]*x);
}
}
cout<<f[V];
return 0;
}
二维费用的背包问题是指:对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。设这两种代价分别为代价1和代价2,第i件物品所需的两种代价分别为a[i]和b[i]。两种代价可付出的最大值(两种背包容量)分别为V和U。物品的价值为w[i]。
算法
费用加了一维,只需状态也加一维即可。设f[i][v][u]表示前i件物品付出两种代价分别为v和u时可获得的最大价值。状态转移方程就是:
f [ i ] [ v ] [ u ] = m a x f [ i − 1 ] [ v ] [ u ] , f [ i − 1 ] [ v − a [ i ] ] [ u − b [ i ] ] + w [ i ] f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]} f[i][v][u]=maxf[i−1][v][u],f[i−1][v−a[i]][u−b[i]]+w[i]
https://blog.csdn.net/qq_33765907/article/details/50726151
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
//https://www.cnblogs.com/zhangmingcheng/p/3940332.html
#include
using namespace std;
int a[101][101],f[101];
int main()
{
int n,m,i,j,k;
while(cin >> n >> m && (n != 0 || m != 0))
{
memset(f,0,sizeof(f));
for(i = 1; i <= n; i++)
for(j = 1; j <= m; j++)
cin >> a[i][j];
for(i = 1; i <= n; i++) //第一重循环:分组数
for(j = m; j >= 0; j--) //第二重循环:容量体积
for(k = 0; k <= j; k++) //第三重循环:属于i组的k
f[j] = max(f[j],f[j-k]+a[i][k]);
cout << f[m] << endl;
}
return 0;
}
这种背包问题的物品间存在某种“依赖”的关系。也就是说,i依赖于j,表示若选物品i,则必须选物品j。为了简化起见,我们先设没有某个物品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。
https://www.cnblogs.com/hrj1/p/11184616.html