01背包
优化之前的代码
优化之后的代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxv = 110;
const int maxn = 10100;
int w[maxn], dp[maxv];
//w为每个硬币的价值
//dp[i]为 重量为i时,可以放的东西的最大价值
bool choice[maxn][maxv], flag[maxn];
//choice[i][v]存放的是:当背包的重量为v时,第i个商品是否放入了背包
//dp[m] //价钱为m时,背包中所放的商品的最大值
bool cmp(int a, int b) {
return a > b;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
//存储每个硬币的币值
for(int i = 1; i <= n; i++) {
scanf("%d", &w[i]);
}
//对每个硬币的币值进行从大到小排序
//但是想要保证序列“最小”,就必须将原面值递减排序。
//在回溯中每次遇到L(i - 1, v - w[i]) + w[i]这种情况,
//就决定选择w[i],因为此时w[i]总是最小的。
sort(w + 1, w + 1 + n, cmp);
//初始化背包值
fill(dp, dp + maxv, 0);
//生成状态方程的中间值
for(int i = 1; i <= n; i++) {
for(int v = m; v >= w[i]; v--) {
//每一次推导V(i)(j)是通过V(i-1)(j-w(i))来推导的,
//所以一维数组中j的扫描顺序应该从大到小(capacity到0),
//否者前一次循环保存下来的值将会被修改,从而造成错误。
if(dp[v] <= dp[v - w[i]] + w[i]) { //注意相等时也要向背包中放东西
//通过状态转换方程对每个点的状态进行量化
dp[v] = dp[v - w[i]] + w[i];
choice[i][v] = 1; //当背包重量为v时,向背包中放入第i件东西
} else {
choice[i][v] = 0; //不放
}
}
}
if(dp[m] != m) //价钱为m时,背包中所放的商品的最大值不为m
printf("No Solution");
else {
int k = n, num = 0, v = m;
while(k >= 0) {
if(choice[k][v] == 1) { //在重量为v时,第k件商品是否放入了背包
flag[k] = 1;
v -= w[k]; //所需币值进行相应的变化
num++;
} else {
flag[k] = false;
}
k--;
}
//输出背包中的结果
for(int i = n; i >= 1; i--) {
if(flag[i] == true) {
printf("%d", w[i]);
num--;
if(num > 0)
printf(" ");
}
}
}
return 0;
}