hdu 2546 详解用0-1背包思想解决问题

这道题,我一共WA了5次。

基本上,每一次我都发现了自己思维上的问题。

想花一点时间认真的来解释一下我的解法。


首先附AC代码:

#include<iostream>
#include<algorithm>
using namespace std;

#define N 1005

int n;
int v[N];
int val;
int re[N][N];

void zeroOneBack(){
	int i = n - 1,j,k,temp1,temp2;
	for (j = 0; j < 5; j++){
		re[i][j] = j;
	}
	for (; j <= val; j++){
		re[i][j] = j - v[i];
	}
	for (k = i - 1; k >= 0; k--){
		for (j = 0; j < 5 ; j++){
			re[k][j] = re[k + 1][j];
		}
		for (; j <= val; j++){
			temp1 = re[k + 1][j];
			if (j - v[k] >= 0){
				temp2 = re[k + 1][j - v[k]];
			}
			else{
				temp2 = j - v[k];
			}
			re[k][j] = temp1 < temp2 ? temp1 : temp2;
		}
	}
}

int main(){
	int i;
	while (cin >> n&&n != 0){
		for (i = 0; i < n; i++){
			cin >> v[i]; 
		}
		sort(v, v + n);
		cin >> val;
		zeroOneBack();
		cout <<re[0][val]<< endl;
	}
	return 0;
}


我看了网上的解法,大部分人都先对价值最高的先进行处理,然后再进行0-1背包。

我一开始不理解这种做法,其实这种做法是有它的必要性的。一会详细的解释。


数组 re[i][j] 代表 i物品在饭卡中还剩下j元时,有可能使得饭卡能达到的最低金额。

比如re[3][6] = -2 表示如果我要选择买不买3号时,当我饭卡内还剩下6元时,可能能达到的最低金额是-2元。


0-1背包问题自底向上,所以从最后一个物品开始,

首先进行初始化,

如果饭卡内的金额小于5,则不管够不够,都不能买(要特别注意这个初始化)

所以

for (j = 0; j < 5; j++){
		re[i][j] =<span style="color:#ff0000;"> j</span>;
}


对于最后一个物品而言,如果饭卡内的金额大于5元,则都可以买

for (; j <= val; j++){
		re[i][j] = j - v[i];
}
这里就要特别提出在进入0-1背包之前,我先进行了排序:

sort(v, v + n);
因为,直接0-1背包,价格大的物品再前,而价格小的物品在后,价格大的物品就会把价格小的物品被选择的机会给剥夺,

这里我给出一组测试用例,大家比较一下就知道了。

如果不排序,

10
3 10 10 10 11 1 3 4 5 6
7
这组用例的结果会是 -4

10
3 10 10 10 1 11 3 4 5 6
7

这组用例的结果会是 -5


然后进行0-1背包的选择,这个就没什么好说的啦。


另外提供几组测试用例:

2

1 1

5

4

1

10

3

3


能够通过这些的话

我相信你应该能够AC啦!


继续加油刷DP

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值