背包问题 综合练习

【问题描述】
 
问题1:装满背包
  给出 N 个物品,第 i 个物品的体积为 v[i],价值为 p[i],现在需要选择一些物品装满容量为 C 的背包,所能获得的最大价值,如果不能装满,则输出-1。


问题2:K背包
  给出 N 个物品,第i个物品的体积为 v[i],价值为 p[i],现在需要选择 K 个装入容量为 C 的背包,所能获得的最大价值,如果无解,则输出-1。 
 
【输入格式】
 
  第 1 行:两个整数 C 和 N 。
  接下来的N行:每行两个整数,表示 v[i] 和 p[i] 。
  最后一行,一个整数 K (针对问题2)。


 
【输出格式】
 
  第 1 行:一个整数,表示问题1的解,不能装满,则输出-1。
  第 2 行:一个整数,表示问题2的解,如果无解,则输出-1。


 
【输入样例】
 
【样例1】
  10 5
  2 2
  8 7
  3 3
  5 4
  7 8
  3


【样例2】
  10 5
  2 2
  8 7
  3 3
  5 4
  7 8
  4


【样例3】
  16 5
  3 3
  1 3
  2 1
  5 4
  4 6
  3


 
【输出样例】
 
【样例1】
  11
  9


【样例2】
  11
  -1


【样例3】
  -1
  13


【数据范围】
 
   1<=K<=N<=100
  1<=v[i]<=C<=20000

  1<=p[i]<=1,000,000

【分析】

和普通的0-1背包不太一样

问题一:

状态方程:f(i,j)表示前i个背包选物品刚好放满j容量的背包所能获得的最大价值

状态转移:f(i,j)=max{ f(i-1,j) , f( i-1,j-v[i] )+p[i] }

边界(重点):f(0,0)=0 f(0,j)=-oo (-oo表示不可行) 

问题二:

f(i,j,k) 表示前i个背包中选j个体积不超过k所能获得的最大价值 
f(i,j,k)=max:f(i-1,j,k),f(i-1,j-1,k-v[i])+p[i]

边界:f(i,0,k)=0 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,c,k,v[105],p[105];
int ans[20003],a[102][20003]; 
int main()
{
	//第一问 
	memset(ans,0xaf,sizeof(ans));//初始化-oo 
	ans[0]=0;
	scanf("%d%d",&c,&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&p[i]);
	scanf("%d",&k); 
	for(int i=1;i<=n;i++)
	{
		for(int j=c;j>=v[i];j--) 
		{
			ans[j]=max(ans[j],ans[j-v[i]]+p[i]);
		}
	}
	if(ans[c]>=0) printf("%d\n",ans[c]);
	else printf("-1\n");
/*
对递推方程的分析:
f(i,j,k) 表示前i个背包中选j个体积不超过k所能获得的最大价值 
f(i,j,k)=max:f(i-1,j,k),f(i-1,j-1,k-v[i])+p[i]
边界:f(i,0,k)=0 
*/
	memset(a,0xaf,sizeof(a));
	for(int i=0;i<=20000;i++) a[0][i]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=k;j>=1;j--)
		{
			for(int q=c;q>=v[i];q--)
				a[j][q]=max(a[j][q],a[j-1][q-v[i]]+p[i]); 
		}
	}
	if(a[k][c]>=0) printf("%d\n",a[k][c]);
	else printf("-1\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hi_ker/article/details/79700215
今日推荐