1. Knapsack Problem. There are 5 items that have a value and weight list below, the knapsack can contain at most 100 Lbs. Solve the problem both as fractional knapsack and 0/1 knapsack.
分数背包问题:
#include <cstdlib>
#include <iostream>
using namespace std;
int value[5] = {20, 30, 65, 40, 60};
int weight[5] = {10, 20, 30, 40, 50};
double valueperweight[5] = {2, 1.5, 2.1, 1, 1.2};
int x[5];
int flag[5];
double lastv;
int lastw;
int find()
{
double max = 0;
int v;
for(int i = 0; i < 5; i++)
{
if(valueperweight[i] > max && flag[i] == 0)
{
max = valueperweight[i];
v = i;
}
}
flag[v] = 1;
return v;
}
void FractionalKnapsack()
{
int c = 100, k;
for(int i = 0; i < 5; i++)
{
k = find();
cout << k <<endl;
if(weight[k] < c)
{
x[k] = 1;
c -= weight[k];
}
else break;
}
if(weight[k] != c)
{
x[k] = 2;
lastv = c * valueperweight[k];
lastw = c;
}
}
void print()
{
double sum = 0;
for(int i = 0; i < 5; i++)
{
if(x[i] == 1)
{
cout << "value:" << value[i] << " " << "weight:" << weight[i] << " " << "num:" << i;
sum += value[i];
cout << endl;
}
else if(x[i] == 2)
{
cout << "value:" << lastv << " " << "weight:" << lastw << " " << "num:" << i;
sum += lastv;
cout << endl;
}
}
cout << "sum of value:" << sum <<endl;
}
int main(int argc, char *argv[])
{
memset(flag, 0, sizeof(flag));
cout << "Fractional Knapsack:" << endl;
FractionalKnapsack();
print();
system("PAUSE");
return EXIT_SUCCESS;
}
0/1背包问题:
对于背包问题,通常使用的处理方法是搜索。用递归来完成。当背包剩余空间可以放入第i件物品,则第i件物品放入和不放入所能得到的价值取最大。这个算法的时间复杂度是O(2^n),我们可以做一些简单的优化。
由于本题的所有物品的体积均是整数,经过几次的选择后背包的剩余空间可能会相等,在搜索中会重复计算这些结点。所以,如果我们把搜索过程中计算过的结点的值记录下来,以保证不重复计算的话,速度就会提高很多。这是简单的“以空间换时间”。由于计算过程中会出现重叠的结点,符合动态规划中子问题重叠的性质。并且如果通过第N次选择得到的是一个最优解的话,那么第N-1次选择的结果一定也是一个最优解。符合动态规划最有子结构的性质。
DP的三个步骤:
1. 阶段:在前N件物品中,选取若干件放入背包中;
2. 状态:在前N件物品中,选取若干件物品放入所剩空间为W的背包中的所获得的最大价值;
3. 决策:第N件物品放或者不放;
我们可以由此写出动态转移方程:用f[i,j]表示在前i件物品中选择若干件放在所剩空间为j的背包里所能获得的最大价值。f[i,j] = max{f[i - 1, j - wi] + Pi, f[i - 1, j]}。这个
由于是一个二重循环,这个算法的时间复杂度是O(n*w)。
#include <cstdlib>
#include <iostream>
using namespace std;
int value[6] = {0, 20, 30, 65, 40, 60};
int weight[6] = {0, 10, 20, 30, 40, 50};
int c[11] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int flag[6][11];
int map[6][11];
int w = 0, sum = 0;
void Knapsack()
{
int t;
for(int j = 0; j < 10; j++)
map[0][j] = 0;
for(int i = 0; i < 6; i++)
map[i][0] = 0;
for(int i = 1; i < 6; i++)
for(int j = 1; j < 11; j++)
{
if(c[j] >= weight[i])
{
t = (c[j] - weight[i])/10;
if((value[i] + map[i - 1][t]) > map[i - 1][j])
{
map[i][j] = value[i] + map[i - 1][t];
flag[i][j] = 1;
}
else map[i][j] = map[i - 1][j];
}
else map[i][j] = map[i - 1][j];
}
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 11; j++)
cout << map[i][j] << " ";
cout << endl;
}
cout << endl;
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 11; j++)
cout << flag[i][j] << " ";
cout << endl;
}
}
int print(int i, int j)
{
if(i == 0 || j == 0)
{
cout << "weight:" << w << " " << "sum:" << sum << endl;
system("pause");
return 0;
}
if(flag[i][j] == 0)
print(i - 1, j);
else
{
cout << "weight:" << weight[i] << " " << "value:" << value[i] << " " <<endl;
sum += value[i];
w += weight[i];
}
int t = (c[j] - weight[i])/10;
print(i-1, t);
}
int main(int argc, char *argv[])
{
memset(flag, 0, sizeof(flag));
cout << "0-1 Knapsack:" << endl;
Knapsack();
cout << map[5][10] << endl;
print(5, 10);
system("PAUSE");
return EXIT_SUCCESS;
}