动态规划算法:背包问题

动态规划:背包问题

背包容积为 Weight
n 个物体,第 i 个物体的体积为 Wi,价值为 Vi
问:背包最大能够存放的物体价值之和最大为多少?

问题分析:
OPT(i, w) 表示前 i 个物体中,选择一些物体存放入容积为 w 的背包,所选中的所有物体的价值之和最大值。

在前 i 个物体,选择存放入背包的最大值之和,包括两种情况

第一种:第 i 个物体不放入背包
则一定是在 {1, 2, …, i - 1} 个物体中,可用容积为 w 的前提下,选择一些物体放入背包中,第 i 个物体不放入背包中。
OPT(i, w)= OPT(i - 1, w)

第二种:第 i 个物体放入背包
则一定是在 {1, 2, …, i - 1} 个物体中,可用容积为 w - Wi 的前提下,选择一些物体放入背包中,并且加入了第 i 个物体。
为什么是 w -Wi 的前提下?
因为要选择第 i 个物体放入背包,则选择第 i 个物体时,背包中剩余空间容积 >=i 个物体的体积 Wi (否则第 i 个物体是无法放入背包的)
所以背包中现有物体总体积 <= w - Wi
OPT(i, w) = Vi + OPT(i - 1, w - Wi)

建立动态规划基本方程

if (i == 0)
{
    
    
    OPT(i, w) = 0;
}
else if (Wi > w)
{
    
    
    OPT(i, w) = OPT(i - 1, w);
}
else
{
    
    
    OPT(i, w) = Max(OPT(i - 1, w), Vi + OPT(i - 1, w - Wi));
}

逻辑代码如下

    class KnapsackProblem
    {
    
    
        // 物体个数
        private const int Count = 5;

        // 物体体积,创建 Count + 1 个空间的数组,第 i 个物体体积为 W[i]
        private int[] W = new int[Count + 1] {
    
     0, 1, 2, 5, 6, 7 };
        // 物体价值,创建 Count + 1 个空间的数组,第 i 个物体价值为 V[i]
        private int[] V = new int[Count + 1] {
    
     0, 1, 6, 18, 22, 28 };
        // 背包容积
        private const int Weight = 11;

        // 存储动态规划结果,OPT[Count, Weight] 为最终结果
        private int[,] OPT = new int[Count + 1, Weight + 1];

        public KnapsackProblem()
        {
    
    
            int result = Knapsack();
            Console.WriteLine("result:" + result);

            Print();
        }

        private int Knapsack()
        {
    
    
            // 初始化令物体个数为 0 时,选中物体价值 = 0
            for (int w = 0; w <= Weight; ++w)
            {
    
    
                OPT[0, w] = 0;
            }

            // 物体个数遍历,从第 1 个物体开始
            for (int i = 1; i <= Count; ++i)
            {
    
    
                // 容量大小遍历,从容量为 1 开始
                for (int w = 1; w <= Weight; ++w)
                {
    
    
                    // W[i] 第 i 个物体的体积
                    // V[i] 第 i 个物体的价值
                    if (W[i] > w)
                    {
    
    
                        OPT[i, w] = OPT[i - 1, w];
                    }
                    else
                    {
    
    
                        OPT[i, w] = Math.Max(OPT[i - 1, w], V[i] + OPT[i - 1, w - W[i]]);
                    }
                }
            }

            return OPT[Count, Weight];
        }

        private void Print()
        {
    
    
            for (int i = 0; i <= Count; ++i)
            {
    
    
                for (int j = 0; j <= Weight; ++j)
                {
    
    
                    Console.Write(OPT[i, j] + "  ");
                }
                Console.WriteLine();
            }
        }
    }

最终结果为
result = 40, 选择第 3 个和 第 4 个物体放入背包

下图为计算过程以及结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/LIQIANGEASTSUN/article/details/126955858