这道题,我一共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>;
}
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