# 游戏常用算法:动态规划算法-01背包问题

动态规划的原理

动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不同的是,分治法在子问题和子子问题等上被重复计算了很多次,而动态规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。

最优性原理是动态规划的基础,最优性原理是指“多阶段决策过程的最优决策序列具有这样的性质:不论初始状态和初始决策如何,对于前面决策所造成的某一状态而言,其后各阶段的决策序列必须构成最优策略”。

题目描述
有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

在这里插入图片描述只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。
首先要明确这张表是从上到下,从左到右生成的。

01背包的转换方程
f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
i表示第几行,也就是有几个物品,如上图灰色列;j表示当前背包格子的承重,如上图蓝色标题。
Wi指第j件物品的重量,Pi指第i件物品的价值

c#代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Bag01
{
class Program
{

    public class BagItem
    {
        public string Name = "";
        public int Value = 0;

        public BagItem()
        {
            Name = "";
            Value = 0;
        }

        public BagItem(string name, int value)
        {
            Name = name;
            Value = value;
        }
    };

    //--------------------------------------------背包问题------------------------------------------  
    const int maxBagWeight = 10;
    static string[] Name = { "a", "b", "c", "d", "e" };
    static int[] Weight = { 2, 2, 6, 5, 4 };
    static int[] Value = { 6, 3, 5, 4, 6 }; 
    static int nCount = Weight.Length;//物品的总个数

    static void Calc01Package(BagItem[,] itemBuffer)
    {
        //首先进行参数检测  
        if (null == itemBuffer)
	        return;

        //最后一行,以为只有最后一个物品(第5列)Weight[5] = 4,所以格子小于4的都是0,放不进去,大于等于4的,放入价值是Value[5]=6
        for (int curBagWeight = 0; curBagWeight <= maxBagWeight; ++curBagWeight)
        {
	        //如果当前承重量小于最后一个物品的重量,放不进去,价值为0
	        if (curBagWeight< Weight[0])
	        {
		        itemBuffer[0,curBagWeight].Value = 0;
		        itemBuffer[0,curBagWeight].Name = "";
	        }
	        //如果当前承重量大于最后一个物品的重量,放人最后一个物品的价值
	        else
	        {
		        itemBuffer[0,curBagWeight].Value = Value[0];
		        itemBuffer[0,curBagWeight].Name = Name[0];
	        }

	        //cout << memory[maxItemCount][curBagWeight] << " ";
        }
        //接下来就是动态规划的体现,对剩下的n-1个物品放入,也就是填充memory数组  
        for (int row = 1; row < Name.Length; ++row)
        {
	        for (int curBagWeight = 1; curBagWeight <= maxBagWeight; ++curBagWeight) //格子编号,相当于格子的承重数
	        {
		        if (curBagWeight < Weight[row])										//这里保持和下面一样就可以了
		        {
			        itemBuffer[row,curBagWeight].Value = itemBuffer[row - 1,curBagWeight].Value;
			        itemBuffer[row,curBagWeight].Name = itemBuffer[row - 1,curBagWeight].Name;
		        }
		        else
		        {
			        itemBuffer[row,curBagWeight].Value = itemBuffer[row - 1,curBagWeight].Value > itemBuffer[row - 1,curBagWeight - Weight[row]].Value + Value[row] ?
                        itemBuffer[row - 1,curBagWeight].Value : itemBuffer[row - 1,curBagWeight - Weight[row]].Value + Value[row];

			        itemBuffer[row,curBagWeight].Name = itemBuffer[row - 1,curBagWeight].Value > itemBuffer[row - 1,curBagWeight - Weight[row]].Value + Value[row] ?
                        itemBuffer[row - 1,curBagWeight].Name : itemBuffer[row - 1,curBagWeight - Weight[row]].Name + Name[row];
		        }
	        }
        }
    }

    static void Main(string[] args)
    {
        BagItem[,] itemBuffer = 
        {
             {  new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem() },
             {  new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem() },
             {  new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem() },
             {  new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem() },
             {  new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem(), new BagItem() },
        };

        Calc01Package(itemBuffer);

        Console.WriteLine("背包价值");
        for (int row = 0; row < nCount; ++row)
        {
	        for (int col = 0; col <= maxBagWeight; ++col)
	        {
		        Console.Write("{0,-5}", itemBuffer[row,col].Value);    //使用printf在这里比较方便指定行宽  
	        }
            Console.WriteLine();

        }

        Console.WriteLine("物品放置详情");
        for (int row = 0; row < nCount; ++row)
        {
	        for (int col = 0; col <= maxBagWeight; ++col)
	        {
                if(string.IsNullOrEmpty(itemBuffer[row, col].Name))
                {
                    Console.Write("{0,-5}", "."); 
                }
                else
                {
                    Console.Write("{0,-5}", itemBuffer[row, col].Name);
                }
                
	        }
            Console.WriteLine();
        }

        Console.ReadKey();

        return;
    }
}

}
运行结果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值