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

来源:互联网 发布:php yaf导出excel表格 编辑:程序博客网 时间:2024/05/27 20:05

        在这个暑假过程中,又学习到了很多的算法,发现算法真的是无处不在,很神奇。下面来简单介绍一下动态规划问题。

        算法在我们生活中特别常见,例如一个小偷拿着容量为10的背包去商店偷东西,商店里有5种商品,每个商品的(重量,价值)分别为(2,6)、(2,3)、(6,5)、(5,4)、(4,6),小偷怎样才能在不超过背包容量的情况下,偷取价值总和最大的物品呢?


动态规划的思想:


1)最优子结构:如果一个问题的最优解中包含了子问题的最优解,就说该问题具有最优子结构。

2)重叠子问题:是指用来解原问题的递归算法可反复的解同样的子问题,而不总在产生新问题。即当一个递归算法不断地调用同一个问题时,就说该问题包含重叠子问题。

    

解题步骤:


1)刻画0-1背包问题的最优解结构


2)定义最优解的值


                         0                                                  ,i=0或w=0

 C[i,w]=             C[i-1,w]                                         ,wi >w

                         max{ C[i-1,w-wi] + vi  ,  C[i-1,w] }    ,i>0且wi <=w


3)计算背包问题最优解的值

 

  #region  0-1背包问题 最优解的值            int[] w ={ 2, 2, 6, 5, 4 }; //物品重量            int[] v = { 6, 3, 5, 4, 6 }; //物品价值            int c = 10;            //背包容量            int[] x = new int[5];  //记录物品装入情况,0表示不装入,1表示装入            x[0] = 1; //初始值表示第一个物品已装入背包            int[,] m = new int[5, c + 1];//二维表,其中第0列表示背包容量为0时背包的最大价值为0            // 初始化第一行,即背包中装入第一件物品                                            for (int j = 1; j <= c; j++)            {                if (j >= w[0])                {                    m[0, j] = v[0];  //为什么要写这一段代码,不直接在下面的代码中将 for (int i = 1; i < 5; i++)中i从0开始?(因为  if (j < w[i]) m[i, j] = m[i - 1, j];如果i从0开始,那么m[-1,i],就会越界                }            }            // 背包中依次装入其他的物品            for (int i = 1; i < 5; i++)            {                for (int j = 1; j <= c; j++)                {                    if (j < w[i]) m[i, j] = m[i - 1, j]; //w[i]不装入背包                    else                    {                        if (m[i - 1, j - w[i]] + v[i] > m[i - 1, j]) m[i, j] = m[i - 1, j - w[i]] + v[i]; //选择价值较大者                        else m[i, j] = m[i - 1, j];                    }                }            }            label1.Text = "背包的最大价值为:" + m[w.Length - 1, c];            #endregion

重叠子问题:这个是在填写上面这张表格的时候可以很好的体现,例如你算C[2,2]的时候,利用公式展开C[2,2]=max { C[1,0]+6 , C[1,2] },C[1,0]与C[1,2]就不用再算一遍,直接用表格第一行算出来的结果就可以啦。


4)根据计算结果构造问题最优解


判断 C[i,w]   ,  C[i-1,w] 的值是否相等,若相等,则说明Xi=0,不在背包里面,否则,在里面。

特别注意的地方:编号为0的物品不能用上面的公式,计算是否在里面(会出现越界错误),利用m[0,c]=0来判断,若等于0,不在里面。

  #region  显示最优解            for (int i = 4; i >= 1; i--)            {                if (m[i,c] > m[i - 1,c])                {                    x[i] = 1; //装入背包                    c -= w[i]; //更新背包目前最大容量                }                else x[i] = 0; //没有装入背包            }            if (m[0, c] == 0) //判断第一个物品是否放入包中            {                x[0] = 0;            }            else            {                x[0] = 1;            }                        for (int i = 0; i < 5; i++)            {                if (x[i] == 1)                {                    int a = i + 1;                    label2.Text =label2 .Text +"   " +a.ToString() ; //输出最优解                }            }            #endregion

最终结果为:最大价值为15,装入背包的物品为第1、2、5个