标签:amp 组成 描述 mes http 必须 package 需要 需求量
例题参考《信息学奥赛一本通》
初始化分两种情况
1、如果背包要求正好装满则初始化 f[0] = 0, f[1~v] = -INF;
2、如果不需要正好装满 f[0~v] = 0;
有N件物品和一个容量为V的背包。第i件物品的费用(即体积,下同)是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
例题
【问题描述】
一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若每种物品只有一件求旅行者能获得最大总价值。
【输入格式】
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
【输出格式】
仅一行,一个数,表示最大总价值。
【样例输入】package.in
10 4
2 1
3 3
4 5
7 9
【样例输出】package.out
12
解法一
#include<cstdio>
using namespace std;
const int maxn=201,maxn=31;
int m,n;
int w[maxn],c[maxn];
int f[maxn][maxm];
int max(int x,int y) { x>y?x:y;} //求x和y最大值
int main()
{
scanf("%d%d",&m,&n); //背包容量m和物品数量n
for (int i=1;i<=n;i++) //在初始化循环变量部分,定义一个变量并初始化
scanf("%d%d",&w[i],&c[i]); //每个物品的重量和价值
for(int i=1;i<=n;i++) // f[i][v]表示前i件物品,总重量不超过v的最优价值
for(int v=m;v>0;v--)
if(w[i]<=v)
f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i]);
else
f[i][v]=f[i-1][v];
printf("%d",f[n][m]); // f[n][m]为最优解
return 0;
}
解法二
#include<cstdio>
using namespace std;
const int maxm=2001,maxn=31;
int m,n;
int w[maxn],c[maxn];
int f[maxm];
int main()
{
scanf("%d%d",&m,&n); //背包容量m和物品数量n
for (int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]); //每个物品的重量和价值
for(int i=1;i<=n;i++) //设f(v)表示重量不超过v公斤的最大价值
for(int v=m;v>=w[i];v--)
if(f[v-w[i]]+c[i]>f[v])
f[v]=f[v-w[i]]+c[i];
printf("%d",f[m]); // f(m)为最优解
return 0;
}
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
例题
【问题描述】
设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。
【输入格式】
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
【输出格式】
仅一行,一个数,表示最大总价值。
【样例输入】knapsack.in
10 4
2 1
3 3
4 5
7 9
【样例输出】knapsack.out
max=12
代码
解法一
#include<cstdio>
using namespace std;
const int maxm=201,maxn=31;
int m, n;
int w[maxn],c[maxn];
int f[maxn][maxm];
int main()
{
scanf("%d%d",&m,&n); //背包容量m和物品数量n
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]); //每个物品的重量和价值
for(int i=1;i<=n;i++) //f[i][v]表示前i件物品,总重量不超过v的最优价值
for(int v=1;v<=m;v++)
if(v < w[i])
f[i][v]=f[i-1][v];
else
if(f[i-1][v]>f[i][v-w[i]]+c[i])
f[i][v]=f[i-1][v];
else
f[i][v]=f[i][v-w[i]]+c[i];
printf("max=%d",f[n][m]); // f[n][m]为最优解
return 0;
}
解法二
#include<cstdio>
using namespace std;
const int maxm=2001,maxn=31;
int n,m,v,i;
int c[maxn],w[maxn];
int f[maxm];
int main()
{
scanf("%d%d",&m,&n); //背包容量m和物品数量n
for(i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);
for(i=1;i<=n;i++)
for(v=w[i];v<=m;v++) //设 f[v]表示重量不超过v公斤的最大价值
if(f[v-w[i]]+c[i]>f[v])
f[v]=f[v-w[i]]+c[i];
printf("max=%d\n",f[m]); // f[m]为最优解
return 0;
}
有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
#include<iostream>
using namespace std;
int n,m;
int f[6002];
int v[6002],w[6002],s[6002];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i]>>s[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
for(int k=0;k<=s[i];k++)
{
if(j-k*v[i]<0)
break;
f[j]=max(f[j],f[j-k*v[i]]+k*w[i]);
}
cout<<f[m];
}
解法二(二进制优化)
#include<iostream>
using namespace std;
int n,m;
int f[6002];
int v[6002],w[6002];
int v1,w1,s;
int n1=0;
int main()
{
cin>>n>>m;
while(n--)//把每种划分成不同种类的
{
cin>>v1>>w1>>s;
for(int i=1;i<=s;i*=2)//二进制分解
//把14分成1,2,4,6多出1在后面打包
{
v[++n1]=i*v1;
w[n1]=i*w1;
s-=i;
}
if(s>0)//多出来的一起打包
{
v[++n1]=s*v1;
w[n1]=s*w1;
}
}
for(int i=1;i<=n1;i++)
for(int j=m;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
cout<<f[m];
}
将01背包、完全背包、多重背包混合起来。也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。
#include<cstdio>
using namespace std;
int m,n;
int w[31],c[31],p[31];
int f[201];
int max(int x,int y)
{
return
x>y?x:y;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&w[i],&c[i],&p[i]);
for(int i=1;i<=n;i++)
if(p[i]==0)
{ //完全背包
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
}
else
{
for(int j=1;j<=p[i];j++) //01背包和多重背包
for(int k=m;k>=w[i];k--)
f[k]=max(f[k],f[k-w[i]]+c[i]);
}
printf("%d",f[m]);
return 0;
}
二维费用的背包问题是指:对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。设这两种代价分别为代价1和代价2,第i件物品所需的两种代价分别为a[i]和b[i]。两种代价可付出的最大值(两种背包容量)分别为V和U。物品的价值为c[i]。
#include<cstdio>
#include<cstring> //初始化memset要用到
using namespace std;
int v,u,k;
int a[1001],b[1001],c[1001];
int f[101][101];
int main()
{
memset(f,127,sizeof(f)); //初始化为一个很大的正整数
f[0][0]=0;
scanf("%d%d%d",&v,&u,&k);
for(int i=1;i<=k;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);
for(int i=1;i<=k;i++)
for(int j=v;j>=0;j--)
for(int l=u;l>=0;l--)
{
int t1=j+a[i],t2=l+b[i];
if(t1>v)
t1=v; //若氮、氧含量超过需求,可直接用需求量代换,
if(t2>u)
t2=u; //不影响最优解
if(f[t1][t2]>f[j][l]+c[i])
f[t1][t2]=f[j][l]+c[i];
}
printf("%d",f[v][u]);
return 0;
}
有N件物品和一个容量为V的背包。第i件物品的费用是w[i],价值是c[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
例题
【问题描述】
一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
【输入格式】
第一行:三个整数,V(背包容量,V<=200),N(物品数量,N<=30)和T(最大组号,T<=10);
第2..N+1行:每行三个整数Wi,Ci,P,表示每个物品的重量,价值,所属组号。
【输出格式】
仅一行,一个数,表示最大总价值。
【样例输入】group.in
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
【样例输出】group.out
20
代码
#include<cstdio>
using namespace std;
int v,n,t;
int w[31],c[31];
int a[11][32],f[201];
int main()
{
scanf("%d%d%d",&v,&n,&t);
for(int i=1;i<=n;i++)
{
int p;
scanf("%d%d%d",&w[i],&c[i],&p);
a[p][++a[p][0]]=i;
}
for(int k=1;k<=t;k++)
for(int j=v;j>=0;j--)
for(int i=1;i<=a[k][0];i++)
if (j >= w[a[k][i]])
{
int tmp=a[k][i];
if(f[j]<f[j-w[tmp]]+c[tmp])
f[j]=f[j-w[tmp]]+c[tmp];
}
printf("%d",f[v]);
return 0;
}
这种背包问题的物品间存在某种“依赖”的关系。也就是说,i依赖于j,表示若选物品i,则必须选物品j。为了简化起见,我们先设没有某个物品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。
这个问题由NOIP2006金明的预算方案一题扩展而来。遵从该题的提法,将不依赖于别的物品的物品称为“主件”,依赖于某主件的物品称为“附件”。由这个问题的简化条件可知所有的物品由若干主件和依赖于每个主件的一个附件集合组成。
#include<iostream>
using namespace std;
int n,m;
int v[80],p[80],q[80];
int s[40400],t[40400];//s数组存最终的答案 t数组存过渡答案
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>v[i]>>p[i]>>q[i];
p[i]=v[i]*p[i];//先算出代价
}
for(int i=1;i<=m;i++)
{
if(q[i]==0)
{
for(int j=1;j<=v[i];j++)
t[j]=0;//比v[i]小的答案修改不了赋值成0
for(int j=v[i];j<=n;j++)
{
t[j]=s[j-v[i]]+p[i];//修改比v[i]大的答案
}
for(int j=1;j<=m;j++)//寻找i的附件
{
if(q[j]==i)//找到i的附件
{
for(int k=n;k>=v[i]+v[j];k--)//必须要取主件所以k>=v[i]+v[j](分组背包思想)
{
t[k]=max(t[k],t[k-v[j]]+p[j]);//01背包把每组打包
}
}
for(int k=v[i];k<=n;k++)
if(t[k]>s[k])
s[k]=t[k];//替换有比原有答案大的新答案
}
}
}
cout<<s[n];
}
对于一个给定了背包容量、物品费用、物品间相互关系(分组、依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。
对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是01背包中的物品,转移方程即为f[i][v]=sum{f[i-1][v],f[i-1][v-w[i]]+c[i]},初始条件f[0][0]=1。
事实上,这样做可行的原因在于状态转移方程已经考察了所有可能的背包组成方案。
【问题描述】
给你一个n种面值的货币系统,求组成面值为m的货币有多少种方案。样例:设n=3,m=10,要求输入和输出的格式如下:
【样例输入】money.in
3 10 //3种面值组成面值为10的方案
1 //面值1
2 //面值2
5 //面值5
【样例输出】money.out
10 //有10种方案
#include<cstdio>
int m,n;
int a[1001];
long long f[10001]; //注意要用long long
int main()
{
scanf("%d%d",&n,&m); //n种面值的货币,组成面值为m
for(int i=1;i<=n;i++)
scanf("%d",&a[i]); //输入每一种面值
f[0]=1;
for(int i=1;i<=n;i++)
for(int j=m;j>=a[i];j--) //f[j]表示面值为j的总方案数
for(int k=1;k<=j/a[i];k++)
f[j]+=f[j-k*a[i]];
printf("%lld",f[m]); // f[m]为最优解
return 0;
}
总的来说背包问题并不难理解
主要是题目的灵活性需要考虑到底要使用什么背包
还有 每个背包的代码基本相似
但却有个别的差别
所以要搞清楚每个变量的定义
最好是要把代码背下来考试时才不会want to go die
标签:amp 组成 描述 mes http 必须 package 需要 需求量
原文地址:https://www.cnblogs.com/BrokenString/p/9279544.html