问题描述:
假设现有容量m kg的背包,另外有i个物品,重量分别为w[1] w[2] ... w[i] (kg),价值分别为p[1] p[2] ... p[i] (元),将哪些物品放入背包可以使得背包的总价值最大?最大价值是多少?
(示例一:m=10 i=3 重量和价值分别为 3kg-4元 4kg-5元 5kg-6元 )
1,穷举法(把所有情况列出来,比较得到 总价值最大的情况)
如果容量增大,物品增多,这个方法的运行时间将成指数增长
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _01背包问题___穷举法
{
class Program
{
static void Main(string[] args)
{
int m;
int[] w = { 0, 3, 4, 5 };
int[] p = { 0, 4, 5, 6 };
Console.WriteLine(Exhaustivity(10, w, p));
Console.WriteLine(Exhaustivity(3, w, p));
Console.WriteLine(Exhaustivity(4, w, p));
Console.WriteLine(Exhaustivity(5, w, p));
Console.WriteLine(Exhaustivity(7, w, p));
Console.ReadKey();
}
public static int Exhaustivity(int m,int[] w,int[] p)
{
int i = w.Length-1;//物品的个数
int maxPrice = 0;
for (int j = 0; j < Math.Pow(2, m); j++)
{
//取得j 上某一个位的二进制值
int weightTotal = 0;
int priceTotal = 0;
for (int number = 1; number <= i; number++)
{
int result = Get2(j, number);
if (result == 1)
{
weightTotal += w[number];
priceTotal += p[number];
}
}
if (weightTotal <= m &&priceTotal>maxPrice )
{
maxPrice = priceTotal;
}
}
return maxPrice;
}
//取得j上第number位上的二进制值,是1还是0
public static int Get2(int j,int number)
{
int A = j;
int B = (int)Math.Pow(2, number - 1);
int result = A & B;
if (result == 0)
return 0;
return 1;
}
}
}
2, 递归求解
(1)递归求解-自顶向下(不带备忘录)
/****************************************************
文件:Program.cs
作者:黄山学院--Li Qingshan
邮箱: 2781838262@qq.com
日期:2020/06/15 12:28
功能:
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 背包问题_递归法
{
class Program
{
static void Main(string[] args)
{
int[] weightArr = { 0, 3, 4, 5 };
int[] priceArr = { 0, 4, 5, 6 };
Console.WriteLine(UpDown(10, 3, weightArr, priceArr));
Console.WriteLine(UpDown(3, 3, weightArr, priceArr));
Console.WriteLine(UpDown(4, 3, weightArr, priceArr));
Console.WriteLine(UpDown(5, 3, weightArr, priceArr));
Console.WriteLine(UpDown(7, 3, weightArr, priceArr));
Console.ReadKey();
}
static int UpDown(int m, int count, int[] weightArr, int[] priceArr)
{
if (m == 0 || count == 0)
{
return 0;
}
if (weightArr[count] > m)
{
return UpDown(m, count - 1, weightArr, priceArr);
}
else
{
int maxPrice1 = priceArr[count] + UpDown(m - weightArr[count], count - 1, weightArr, priceArr);
int maxPrice2 = UpDown(m, count - 1, weightArr, priceArr);
if (maxPrice1 > maxPrice2)
{
return maxPrice1;
}
return maxPrice2;
}
}
}
}
(2)递归求解-自顶向下(带备忘录)
/****************************************************
文件:Program.cs
作者:黄山学院--Li Qingshan
邮箱: 2781838262@qq.com
日期:2020/06/16 12:30
功能:
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 背包问题_动态规划_自顶向下_
{
class Program
{
static void Main(string[] args)
{
int[] weightArr = { 0, 3, 4, 5 };
int[] priceArr = { 0, 4, 5, 6 };
int[,] memo = new int[100, 100];
Console.WriteLine(UpDown(10, 3, weightArr, priceArr, memo));
Console.WriteLine(UpDown(3, 3, weightArr, priceArr, memo));
Console.WriteLine(UpDown(4, 3, weightArr, priceArr, memo));
Console.WriteLine(UpDown(5, 3, weightArr, priceArr, memo));
Console.WriteLine(UpDown(7, 3, weightArr, priceArr, memo));
Console.ReadKey();
}
static int UpDown(int m, int count, int[] weightArr, int[] priceArr, int[,] memo)
{
if (m == 0 || count == 0)
{
return 0;
}
if (memo[m, count] != 0)
{
return memo[m, count];
}
if (weightArr[count] > m)
{
return UpDown(m, count - 1, weightArr, priceArr, memo);
}
else
{
int temp;
int maxPrice1 = priceArr[count] + UpDown(m - weightArr[count], count - 1, weightArr, priceArr, memo);
int maxPrice2 = UpDown(m, count - 1, weightArr, priceArr, memo);
if (maxPrice1 > maxPrice2)
{
temp = maxPrice1;
}
else
{
temp = maxPrice2;
}
memo[m, count] = temp;
return temp;
}
}
}
}
3,动态规划算法
我们要求得i个物体放入容量为m(kg)的背包的最大价值(记为 c[i,m])。在选择物品的时候,对于每种物品i只有两种选择,即装入背包或不装入背包。某种物品不能装入多次(可以认为每种物品只有一个),因此该问题被称为0-1背包问题
对于c[i,m]有下面几种情况:
a、c[i,0]=c[0,m]=0
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)
(3)动态规划-自底向上
/****************************************************
文件:Program.cs
作者:黄山学院--Li Qingshan
邮箱: 2781838262@qq.com
日期:2020/06/16 12:33
功能:
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 背包问题_动态规划_自下向上_
{
class Program
{
static void Main(string[] args)
{
int[] weightArr = { 0, 3, 4, 5 };
int[] priceArr = { 0, 4, 5, 6 };
Console.WriteLine(UpDown(10, 3, weightArr, priceArr));
Console.WriteLine(UpDown(3, 3, weightArr, priceArr));
Console.WriteLine(UpDown(4, 3, weightArr, priceArr));
Console.WriteLine(UpDown(5, 3, weightArr, priceArr));
Console.WriteLine(UpDown(7, 3, weightArr, priceArr));
Console.ReadKey();
}
static int[,] result = new int[11, 4];
static int UpDown(int m, int count, int[] weightArr, int[] priceArr)
{
if (result[m, count] != 0) return result[m, count];
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= count; j++)
{
if (result[i, j] != 0) continue;
if (weightArr[j] > i)
{
result[i, j] = result[i, j - 1];
}
else
{
int maxPrice1 = priceArr[j] + result[i - weightArr[j], j - 1];
int maxPrice2 = result[i, j - 1];
if (maxPrice1 > maxPrice2)
{
result[i, j] = maxPrice1;
}
else
{
result[i, j] = maxPrice2;
}
}
}
}
return result[m, count];
}
}
}