背包问题问题描述:
假设现有容量m kg的背包,另外有i个物品,重量分别为w[1] w[2] … w[i] (kg),价值分别为p[1] p[2] … p[i] (元),将哪些物品放入背包可以使得背包的总价值最大?最大价值是多少?
(示例一:m=10 i=3 重量和价值分别为 3kg-4元 4kg-7元 5kg-6元 )
一、递归实现(不带备忘的自顶向下法)
将复杂问题分解成小问题,每种物品只有三种情况:1.物品重量超过背包容量,直接计算下一个物品,2.当不超过背包容量时,将当前物品放进去,计算此时价格,3.当不超过背包容量时,将当前物品不放进去,计算此时的价格,比较2和3哪个价格最大,然后决定此物品是否放进背包,利用递归,遍历每一个物品是否放入。
using System;
using System.Text;
namespace cchoop
{
class Program
{
static int num = 0;
public static void Main()
{
int[] weight = { 3, 4, 5 };
int[] price = { 4, 7, 6 };
Console.WriteLine(MaxPrice(10, weight.Length, weight, price));
Console.WriteLine(MaxPrice(3, weight.Length, weight, price));
Console.WriteLine(MaxPrice(4, weight.Length, weight, price));
Console.WriteLine(MaxPrice(5, weight.Length, weight, price));
Console.WriteLine(MaxPrice(7, weight.Length, weight, price));
Console.WriteLine("递归调用了" + num + "次");
}
public static int MaxPrice(int curWeigthBag, int count, int[] weight, int[] price)
{
num++;
if (curWeigthBag <= 0 || count == 0)
{
return 0;
}
int index = count - 1;
if (weight[index] > curWeigthBag)
{
return MaxPrice(curWeigthBag, count - 1, weight, price);
}
//将当前物品放进去
int maxPrice1 = MaxPrice(curWeigthBag - weight[index], count - 1, weight, price) + price[index];
//将当前物品不放进去
int maxPrice2 = MaxPrice(curWeigthBag, count - 1, weight, price);
//比较以上两个数值的大小,返回大的
return maxPrice1 > maxPrice2 ? maxPrice1 : maxPrice2;
}
}
}
二、递归实现(带备忘的自顶向下法)
将计算过的值存储起来,要用的时候直接调用,防止重复计算,性能比第一种解法更高.
代码实现:
using System;
using System.Text;
namespace cchoop
{
class Program
{
static int num = 0;
static int[,] result;
public static void Main()
{
int[] weight = { 3, 4, 5 };
int[] price = { 4, 7, 6 };
//容量指定的背包最大价值
result = new int[11, weight.Length];
Console.WriteLine(MaxPrice(10, weight.Length, weight, price));
Console.WriteLine(MaxPrice(3, weight.Length, weight, price));
Console.WriteLine(MaxPrice(4, weight.Length, weight, price));
Console.WriteLine(MaxPrice(5, weight.Length, weight, price));
Console.WriteLine(MaxPrice(7, weight.Length, weight, price));
Console.WriteLine("递归调用了" + num + "次");
}
public static int MaxPrice(int curWeigthBag, int count, int[] weight, int[] price)
{
num++;
if (curWeigthBag <= 0 || count == 0)
{
return 0;
}
int index = count - 1;
if (result[curWeigthBag, index] != 0)
{
return result[curWeigthBag, index];
}
if (weight[index] > curWeigthBag)
{
result[curWeigthBag, index] = MaxPrice(curWeigthBag, index, weight, price);
return result[curWeigthBag, index];
}
//将当前物品放进去
int maxPrice1 = MaxPrice(curWeigthBag - weight[index], index, weight, price) + price[index];
//将当前物品不放进去
int maxPrice2 = MaxPrice(curWeigthBag, index, weight, price);
int maxPrice;
if (maxPrice1 > maxPrice2)
{
maxPrice = maxPrice1;
}
else
{
maxPrice = maxPrice2;
}
result[curWeigthBag, index] = maxPrice;
//比较以上两个数值的大小,返回大的
return maxPrice;
}
}
}
运行结果:
三、动态规划(自底向上法)
先将规模下的问题先求解出来,再利用其结果求出规模更大的问题
代码实现:
using System;
using System.Text;
namespace cchoop
{
class Program
{
static int[,] result;
public static void Main()
{
int[] weight = { 3, 4, 5 };
int[] price = { 4, 7, 6 };
//容量指定的背包最大价值
result = new int[11, weight.Length];
Console.WriteLine(MaxPrice(10, weight.Length, weight, price));
Console.WriteLine(MaxPrice(3, weight.Length, weight, price));
Console.WriteLine(MaxPrice(4, weight.Length, weight, price));
Console.WriteLine(MaxPrice(5, weight.Length, weight, price));
Console.WriteLine(MaxPrice(7, weight.Length, weight, price));
}
public static int MaxPrice(int curWeigthBag, int count, int[] weight, int[] price)
{
int index = count - 1;
if (result[curWeigthBag, index] != 0)
{
return result[curWeigthBag, index];
}
for (int i = 0; i <= curWeigthBag; i++)
{
for (int j = 0; j < count; j++)
{
if (result[i, j] != 0)
{
continue;
}
if (weight[j] > i)
{
if (j - 1 < 0)
{
result[i, j] = 0;
}
else
{
result[i, j] = result[i, j - 1];
}
}
else
{
//将当前的物品放入背包中
int preMaxPrice1;
if (j - 1 < 0)
{
preMaxPrice1 = 0;
}
else
{
preMaxPrice1 = result[i - weight[j], j - 1];
}
int maxPrice1 = preMaxPrice1 + price[j];
//不将当前的物品放入背包中
int preMaxPrice2;
if (j - 1 < 0)
{
preMaxPrice2 = 0;
}
else
{
preMaxPrice2 = result[i, j - 1];
}
int maxPrice2 = preMaxPrice2;
if (maxPrice1 > maxPrice2)
{
result[i, j] = maxPrice1;
}
else
{
result[i, j] = maxPrice2;
}
}
}
}
return result[curWeigthBag, index];
}
}
}