算法(4)——动态规划背包

容量m kg的背包,另外有i个物品,重量分别为w[1] w[2] ... w[i] kg,价值分别为p[1] p[2] ... p[i] (元),将哪些物品放入背包可以使得背包的总价值最大?最大价值是多少?

我们要求得i个物体放入容量为m(kg)的背包的最大价值(记为 c[im])。在选择物品的时候,对于每种物品i只有两种选择,即装入背包或不装入背包。某种物品不能装入多次(可以认为每种物品只有一个),因此该问题被称为0-1背包问题

  对于c[im]有下面几种情况:

  ac[i,0]=c[0,m]=0   物品数量为0,背包容量为9

  bc[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];
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值