动态规划 - 01背包问题

背包问题问题描述:
假设现有容量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];
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_34937637/article/details/81515199