动态规划——背包

背包经典问题:

背包问题01:

         一个背包容积为T(0<=T<=2000),现在有N(0<N<=1000)个物品,每个物品有一定体积V(1<=V<=5000)。从这N个物品中选取若干个装入背包内,使背包所剩的空间最小。请求出最小的剩余空间?

        代码如下:

#include<cstdio>
using namespace std;
int s[1005];
bool f[3000];
int main(){
	int i,k,ans=0,v,n;
	scanf("%d%d",&v,&n);
	for(i=1;i<=n;i++)scanf("%d",&s[i]);
	f[0]=true;
	for(i=1;i<=n;i++)
	 for(k=v;k>=s[i];k--)//物品有限,反序枚举空间;
	  if(f[k-s[i]])f[k]=true;//f[k-s[i]]=true表示状态f[k]可以通过加上s[i]达到;
	for(i=v;i>0;i--)//找出答案;
	if(f[i]){printf("%d",v-i);return 0;}
}

背包问题02

       
      若每种物品有无限多个。从这N种物品中选取若干个装入背包内,使背包所剩的空间最小。请求出最小的剩余空间?

只需改为正序枚举即可:

	 for(k=s[i];k<=v;k++)
	  if(f[k-s[i]])f[k]=true;
背包问题03

           一个背包容积为T(0<=T<=2000),现在有N(0<N<=1000)个物品,每个物品有一定体积V(1<=V<=5000)。每个物品有一定价值W(1<=W<=5000)。从这N个物品中选取若干个装入背包内,使背包总价值最大。请求出最大价值。

#include<cstdio>
#include<iostream>
using namespace std;
int v[1005],w[1005],f[2000];
int main(){
	int n,tot,i,k,ans=0;
	scanf("%d%d",&tot,&n);
	for(i=1;i<=n;i++)scanf("%d",&v[i]);
	for(i=1;i<=n;i++)scanf("%d",&w[i]);
	for(i=1;i<=n;i++)
	   for(k=tot;k>=v[i];k--)
		f[k]=max(w[i]+f[k-v[i]],f[k]);
	for(i=1;i<=tot;i++)
	ans=max(ans,f[i]);
	printf("%d",ans);
}

    分别讨论1-n个物品,f[i]表示用k的空间所能得到的最大价值。

背包问题  4

Description

一个背包容积为T(0<=T<=2000),现在有N(0<N<=1000)种物品,每种物品有一定体积V(1<=V<=5000)。每种物品有一定价值W(1<=W<=5000).每种物品有无限多个。从这N种物品中选取若干个装入背包内,使背包所剩的空间总价值最大。求出这个最大价值

代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
int v[1005],w[1005],f[2000];
int main(){
	int n,tot,i,k,ans=0;
	scanf("%d%d",&tot,&n);
	for(i=1;i<=n;i++)scanf("%d",&v[i]);
	for(i=1;i<=n;i++)scanf("%d",&w[i]);
	for(i=1;i<=n;i++)
	   for(k=v[i];k<=tot;k++)     //正序枚举即可
		f[k]=max(w[i]+f[k-v[i]],f[k]);
	for(i=1;i<=tot;i++)
	ans=max(ans,f[i]);
	printf("%d",ans);
}
背包问题 5:

Description

有两个背包,一个容积为A,一个容积为B,现在有N个物品,每个物品有一定体积V。 
每个物品有一定的价值W。从这N个物品中选取若干个装入背包内,使背包内物品的价值最大。请求出最大价值?


状态:f[i][j]表示第一个背包使用i,第二个背包使用j的最大价值。

代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
int s[105],w[105],f[305][305],v[105];
int main(){
	int n,i,k,j,ans=0,a,b;
	scanf("%d%d%d",&n,&a,&b);
	for(i=1;i<=n;i++)scanf("%d",&v[i]);
	for(i=1;i<=n;i++)scanf("%d",&w[i]);
	for(i=1;i<=n;i++)
		for(k=a;k>=0;k--)
		   for(j=b;j>=0;j--){   //一定要循环到0
		     if(k-v[i]>=0)f[k][j]=max(f[k][j],w[i]+f[k-v[i]][j]);    //放一号背包
		     if(j-v[i]>=0)f[k][j]=max(f[k][j],w[i]+f[k][j-v[i]]);   //放二号背包
		 }
    for(i=1;i<=a;i++)     //找答案
	for(k=1;k<=b;k++)
	ans=max(ans,f[i][k]);
	printf("%d",ans);
}
背包问题的变形非常多,以下是一道双背包变形:

潜水员 nkoj1123

Description

潜水员为了潜水要使用特殊的装备。他有一个带2种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种的数量的氧和氮。潜水员有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氮。他完成工作所需气缸的总重的最低限度的是多少? 
例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量: 
3 36 120 
10 25 129 
5 50 250 
1 45 130 
4 20 119 
如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。 
你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。

分析:

双背包模型,只是必须填满。

状态:f[i][j]表示i升氧气,j升氮气所需要的最小重量。

代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
int o2,n2,O[1002],N[1002],w[1002],f[100][100],n;
void input(){
	scanf("%d%d%d",&o2,&n2,&n);
	for(int i=1;i<=n;i++)
	scanf("%d%d%d",&O[i],&N[i],&w[i]);
}
void solve(){
	int i,k,j;
	for(i=0;i<=o2;i++)
	   for(k=0;k<=n2;k++)
	      f[i][k]=2e9;    //初值
	for(i=1;i<=n;i++)
	 for(k=o2;k>=0;k--)
	    for(j=n2;j>=0;j--){     //循环到0
	    	int x=k+O[i];
	    	int y=j+N[i];
	    	x=min(x,o2);       
	    	y=min(n2,y);
	    	f[x][y]=min(f[k][j]+w[i],f[x][y]);
	    }
	  printf("%d",f[o2][n2]); 
}
int main(){
	input();
	solve();
}

你可能感兴趣的:(动态规划——背包)