动态规划--0 1 背包问题

一、前提:

动态规划是现在应用广泛的一种算法,变化也很多,下面是0-1背包问题运行过程,可参考。

二、内容:

(一)、动态规划基本思想:

将待求解的问题分解成若干个子问题,先求解子问题,然后根据这些子问题找到原问题的解。

(二)、步骤:

1.找出最优解的性质,并刻画其结构特征

2.递归定义最优解的值

3.以自底向上的方式计算出最优解的值

4.根据计算最优值得到的信息构造一个最优解。

(前三部基本步骤,第四部,可以快速找到最优解)


(三)、性质

1.最优子结构

2.重叠子问题

(四)、动态规划实例 0-1背包问题


按照上述步骤解决问题。

(1)找出最优解的性质,并刻画其结构特征(刻画最优子结构)

0-1背包问题,研究的是在满足背包容量(W)的情况下,背包内装入得最大价值的物品,

0说明物品不在背包里,1说明物品在背包里,也就是找出,在满足物品最大价值情况下,

装入了哪几个物品。

根据题意可以得知有这几个变量:

i表示第几个物品(根据下面解题过程解析)

n表示有几个物品,第几个物品

w背包剩余容量

W背包容量

c[i,w]表示物品价值二维数组

weight[]物品重量的数组

value[]物品价值的数组

x[n]表示是否在包中


(2).递归定义最优解的值


简单解释三个式子

1、物品价值为0,物品i为0或者剩余空间w为0

2、物品i重量大于包的剩余容量w,则i不在包中,所以包内物品价值为i-1个物品的总价值

3、除去前两种情况以外的所有情况

(以逗号为界分成两部分,两部分同时算)

比较当第i个物品被放入包的价值,与不放入价值进行运算,扩展,分到有出口的时候。

(过程是一个递归的过程,需要动手写一遍,便于理解)

(3).以自底向上的方式计算出最优解的值


解读表格:

1.w,背包剩余容量,i表示有几个物品

2.c[1,0]=0

3.背包剩余容量为0,物品为1时装入背包的物品价值为0...以此类推

(4).根据计算最优值得到的信息构造一个最优解。

只要判断物品是否在包中,在包中为1,不在包中为0,即c[i,w]与c[i-1,w]之间价值

是否相等进行判断。c[i,w]与c[i-1,w]二者相等说明i不在包中,所以x[i]=0,反之

x[i]=1,即i在包中。将结果输出,即可得到最优解。

(五)、代码

注意:数组所以表示的是第几个物品

 static void Main(string[] args)
        {
            
            //求最优解的值
            int n=5;
            int i;
            int w;
            int W = 17;
            int[] weight = {0,3,4,7,8,9};//物品重量
            int[] values = {0,4,5,10,11,13};//物品价值
            int [,] c = new int [6,W + 1];//定义价值的数组,考虑背包为0的情况,所以各+1
            
           //背包剩余用量为0
            for ( w = 0; w <= W; w++)
			{
                c[0,w]= 0; 
			}
            //至少有一个物品在包里
            for (i = 1; i <= n; i++)
            {
                c[i, 0] = 0;//剩余容量为0
                for ( w = 1; w <= W; w++)//剩余容量至少为1,最大为W(17)
                {
                    if (weight[i] <= w) //物品重量小于背包剩余容量的时候
	                {
                        if(values[i] + c[i-1,w - weight[i]] > c[i-1,w])//看物品是否在包中
                        {

                             c[i,w] = values[i] + c[i-1,w - weight[i]]; //计算价值                   
                         }
                        else
                        {
                             c[i,w]= c[i-1,w];//不在包中
                        }		 
	                }
                    else
                    {
                        c[i,w]=c[i-1,w]; //重量大于剩余容量                       
                    }
                 }                    
             }

            Console.WriteLine(c[n,W]);
            Console.ReadKey();
//找最优解的值
            int[] x= new int [6];
            for (i = n; i > 1;i-- )
            {
                if (c[i, W] == c[i - 1, W])//判断是否在包中
                {
                    x[i] = 0;
                }
                else 
                {
                    x[i] = 1;
                    W = W - weight[i];//剩余空间减少
                }
            }
            if (c[1,W]== 0 )//判断第一个是否在包中
            {
                x[1] = 0;
            }
            else
            {
                x[1] = 1;
            }
            for ( i = 1; i <=n; i++)
            {
                if (x[i] == 1)//将在包中的输出
                {
                    Console.WriteLine(i.ToString());
                    Console.ReadKey();
                }                       
            }                
        }

总结:

0-1背包问题,需要每一步都自己走一遍才可以理解,直接看代码很难理解,并且不容易记住,但是把上述(2)和(3)好好写一遍就会印象深刻,看代码自然而然就会变得简单。加油,在算法的路上继续前进吧~~


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值