UVa 624 CD && joj 1387 CD 背包问题 yongmou

  题意很简单:n个东西,装入容量为c的背包,怎么使装的东西重量和最大。其实,就是价值等于重量的0/1背包问题。

  UVa 上规模比较小n最大值是20, 用DP把最大容量设置大点就可以AC,但是JOJ上n最大值是100,又没有告诉容量最大有多大,用DP一用就Runtime Error,在设置大点就Memory Limit Exceeded,只好用DFS搜索了。

  DFS搜索的剪枝还挺有技巧性的,其实,一般的讲分支限界法的算法书上都有。具体的剪枝,我都写在代码的注释里了。

DP代码:


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

const int MAX = 104;

int m[MAX][MAX*MAX];// m[i][j]是背包容量为j, 可选择物品为i, i+1, ... , n时, 01背包问题的最优值
int w[MAX]; //重量=价值, 索引从1开始
int x[MAX]; //解向量
int c; //容量
int n;

int max(int a, int b) {
return (a > b ? a : b);
}

void knapsack() {
int i, j;
for (i = 0; i <= c; ++i)
m[
0][i] = 0;
for (i = 0; i <= n; ++i)
m[i][
0] = 0;
for (i = 1; i <= n; ++i)
for (j = 1; j <= c; ++j) {
if (j < w[i])
m[i][j]
= m[i - 1][j];
else
m[i][j]
= max(m[i - 1][j], m[i - 1][j - w[i]] + w[i]);
}
}

void backtrace() {
int max = c;
for (int i = n; i >= 1; --i) {
if(m[i][max] == m[i-1][max])
x[i]
= 0;
else{
x[i]
= 1;
max
-= w[i];
}
}
}
int main() {
// ifstream cin("in");
while (cin >> c) {
cin
>> n;
for (int i = 1; i <= n; i++) {
cin
>> w[i];
}
knapsack();
backtrace();
for(int i=1; i<=n; ++i){
if(x[i] == 1)
cout
<<w[i]<<" ";
}
cout
<< "sum:" << m[n][c] << endl;
}
return 0;
}

DFS搜索代码:

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

const int MAX = 100;
int w[MAX]; //重量=价值, 索引从1开始
int s[MAX]; //从前向后的累积
int mc;
int c; //容量
int n; //磁道数量

void backtrack(int k, int cur) {
if (mc == c)
return; //已经达到最大容量
if (k < 0)
return;
if (cur + s[k] <= mc)
return; //把前面的都加上还没有现在的大
if (cur + w[0] > c)
return; //即使加上最小的也超了

int t = cur + w[k];
if (t <= c && t > mc)
mc
= t;
if (t <= c)
backtrack(k
- 1, t);
backtrack(k
- 1, cur);
}

int main() {
// freopen("in", "r", stdin);
while (scanf("%d %d", &c, &n) != EOF) {
for (int i = 0; i < n; i++)
scanf(
"%d", &w[i]);

sort(w, w
+ n); //排序,使小的放在前面
s[0] = w[0];
for (int i = 1; i < n; ++i)
s[i]
= s[i - 1] + w[i];
mc
= 0;
backtrack(n
- 1, 0);
printf(
"sum:%d\n", mc);
}
return 0;
}
原文地址:https://www.cnblogs.com/liyongmou/p/1774039.html