容量m kg的背包,另外有i个物品,重量分别为w[1] w[2] ... w[i] (kg),价值分别为p[1] p[2] ... p[i] (元),将哪些物品放入背包可以使得背包的总价值最大?最大价值是多少?
我们要求得i个物体放入容量为m(kg)的背包的最大价值(记为 c[i,m])。在选择物品的时候,对于每种物品i只有两种选择,即装入背包或不装入背包。某种物品不能装入多次(可以认为每种物品只有一个),因此该问题被称为0-1背包问题
对于c[i,m]有下面几种情况:
a、c[i,0]=c[0,m]=0 物品数量为0,背包容量为9
b、c[i,m]=c[i-1,m] w[i]>m(最后一个物品的重量大于容量,直接舍弃不用)
w[i]<=m的时候有两种情况,一种是放入i,一种是不放入i
不放入i c[i,m]=c[i-1,m]
放入i c[i,m]=c[i-1,m-w[i]]+p[i]
c[i,m]=max(不放入i,放入i) 物品重量大于背包质量
一、递归实现_带备忘的自顶向下法
class Program
{
//二维数组,第一个为m,第二个为i
public static int[,] result = new int[11, 4];
static void Main(string[] args)
{
int m;
int[] w = { 0, 3, 4, 5 };
int[] p = { 0, 4, 5, 6 };
Console.WriteLine(UpDown(10, 3, w, p));
Console.WriteLine(UpDown(3, 3, w, p));
Console.WriteLine(UpDown(4, 3, w, p));
Console.WriteLine(UpDown(5, 3, w, p));
Console.WriteLine(UpDown(7, 3, w, p));
Console.ReadKey();
}
//m是背包容量
//i是物品个数
//w 物品的重量的数组
//p 物品价值的数组
public static int UpDown(int m, int i, int[] w, int[] p)//返回值是m可以存储的最大价值
{
if (i == 0 || m == 0) return 0;
//result默认值为0,!=0表示计算出来了
if (result[m, i] != 0)
{
return result[m, i];
}
if (w[i] > m)
{
//第i个物品放不进背包,只放前n-i个物品
result[m, i] = UpDown(m, i - 1, w, p);
//先把结果存起来,然后再返回
return result[m, i];
}
else
{
//放进去的价值
int maxValue1 = UpDown(m - w[i], i - 1, w, p) + p[i];
//不放进去的价值
int maxValue2 = UpDown(m, i - 1, w, p);
if (maxValue1 > maxValue2)
{
result[m, i] = maxValue1;
}
else
{
result[m, i] = maxValue2;
}
return result[m, i];
}
}
}
二、背包问题动态规划
class Program
{
static void Main(string[] args)
{
int m;
int[] w = { 0, 3, 4, 5 };
int[] p = { 0, 4, 5, 6 };
Console.WriteLine(BottomUp(10, 3, w, p));
Console.WriteLine(BottomUp(3, 3, w, p));
Console.WriteLine(BottomUp(4, 3, w, p));
Console.WriteLine(BottomUp(5, 3, w, p));
Console.WriteLine(BottomUp(7, 3, w, p));
Console.ReadKey();
}
public static int[,] result = new int[11, 4];
public static int BottomUp(int m, int i, int[] w, int[] p)
{
//每次计算之前判断result最大价值是否计算出来,如果计算出来则返回
if (result[m, i] != 0) return result[m, i];
for (int tempM = 1; tempM < m + 1; tempM++)
{
for (int tempI = 1; tempI < i + 1; tempI++)
{
if (result[tempM, tempI] != 0) continue;
//物品重量大于背包容量
if (w[tempI] > tempM)
{
result[tempM, tempI] = result[tempM, tempI - 1];
}
else
{
//tempI放入背包的情况
int maxValue1 = result[tempM - w[tempI], tempI - 1] + p[tempI];
//tempI没放入背包的情况
int maxValue2 = result[tempM, tempI - 1];
//返回最大价值
if (maxValue1 > maxValue2)
{
result[tempM, tempI] = maxValue1;
}
else
{
result[tempM, tempI] = maxValue2;
}
}
}
}
return result[m, i];
}
}