l蓝桥杯中的背包问题

题目内容:

背包最大允许装载为C, 有n个物品要放进背包,每个物品的重量为w[1],w[2],...w[n],每个物品的价值为v[1],v[2],...v[n], 请选择物品装进背包,使得价值最大。C为整数。
 输入描述
第一行为物体个数n,以及背包容量C;
第二行为n个重量(实数),空格隔开
第三行为n个价值(实数),空格隔开
 输出描述
第一行为最大装载的总价值
第二行为每个物品是否装载,1表示装,0表示不装,中间用空格隔开
(测试数据能保证最优解唯一)
输入样例
5 10
2 2 6 5 4
6 3 5 4 6
输出样例
15

1 1 0 0 1

分析:最开始时没有参考什么资料,那个时候就是自己想,当时想到了性价比这个东西,先对所有算出性价比,然后排序,先把性价比高的东西放进去,然后直到放不下为止,后来实现了自己的想法,但是结果是错误的。其实想验证为什么这个方法是错的很简单,就拿题目中这个例子来说,性价比分别为:1/3,2/3,6/5,5/4,2/3;那么再经过排序后,首先要吧性价比为5/4的东西放进去,但是题目中结果却不是这样的...

自己想办法不成,我后来就看了正在学习的算法书,上面利用动态规划算法实现的,书上清晰的给出了递归公式,按着那个公式最后才搞定了这个题目

#include<stdio.h>
#define M 100
int n/* = 6*/,c/* = 10*/;
int w[M]/* = {0,2,2,6,5,4}*/,p[M]/* = {0,6,3,5,4,6}*/;
int m[M][M];
int x[M];

int min(int a,int b)
{
	if(a >= b)
		return b;
	else if(b > a)
		return a;
	else
		return 0;
}

int max(int a,int b)
{
	if(a >= b)
		return a;
	else if(b > a)
		return b;
	else
		return 0;
}

void Knapsack(int v[],int w[],int c,int n,int m[M][M])
{
	int jMax;
	int i,j;
	jMax = min(w[n] - 1,c);
	for(j = 0;j <= jMax; j++)
		m[n][j] = 0;
	for(j = w[n];j <= c; j++)
		m[n][j] = v[n];
	for(i = n - 1;i > 1; i--)
	{
		jMax = min(w[i] - 1,c);
		for(j = 0;j <= jMax; j++)
			m[i][j] = m[i + 1][j];
		for(j = w[i];j <= c; j++)
			m[i][j] = max(m[i + 1][j],m[i + 1][j - w[i]] + v[i]);
	}
	m[1][c] = m[2][c];
	if(c >= w[1])
		m[1][c] = max(m[1][c],m[2][c - w[1]] + v[1]);
}

void Traceback(int m[M][M],int w[],int c,int n,int x[])
{
	int i;
	for(i = 1;i < n; i++)
	{
		if(m[i][c] == m[i + 1][c])
			x[i] = 0;
		else
		{
			x[i] = 1;
			c = c - w[i];
		}
	}
	x[n] = (m[n][c])?1:0;
	/*printf("m[][] = %d\n",m[n][c]);
	printf("x[n] = %d\n",x[n]);*/
}

int main()
{
	int i;
	scanf("%d",&n);
	scanf("%d",&c);
	for(i = 1;i <= n; i++)
		scanf("%d",&w[i]);
	for(i = 1;i <= n; i++)
		scanf("%d",&p[i]);
	Knapsack(p,w,c,n,m);
	Traceback(m,w,c,n,x);

	printf("%d\n",m[1][c]);//输出最优价值和
	for(i = 1;i <= n; i++)//输出01序列
		printf("%d ",x[i]);
	printf("\n");
	return 0;
}
ps:当时做这个题目是被其中的数组存放方式坑了,这个代码里面数组数据是从下标为1的元素开始存放的,而我们一般用的是从下标为0开始存放的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值