01背包问题

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
状态:用f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值,其状态转移方程为f[i][v]=max{ f[i-1][v],  f[i-1][v-c[i]]+w[i] }。
复杂度分析:
状态数:O(NV), 迁移:O(1)
总复杂度:O(NV)
 
状态f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
对于“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。
如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];
如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。
n状态转移方程:

  f[i][v]=max{ f[i-1][v],  f[i-1][v-c[i]]+w[i] }

时间复杂度O(NV)
由于计算f[i][v]时只用到f[i-1][v]和f[i-1][v-c[i]],在每次主循环中我们以v=V..0的顺序推f[v],这样就保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值,f[v]保存的是状态f[i-1][v]的值。
n伪代码如下:

  for i=1..N

      for v=V..cost

         f[v]=max{f[v], f[v-c[i]] + w[i]};

空间复杂度成功降到O(V)
       // 01背包问题
        public static void Pack(int[] cost, int[] weight, int v)
        {
            int[] volumn = new int[v + 1];
            volumn[0] = 0; //空间复杂度成功降到O(V),如果用二维数组则为o(NV)


            for (int i = 1; i < v + 1; i++)
            {
               // 1). 如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,
                // 这个解的价值为0,所以初始时状态的值也就全部为0了
                // volumn[i] = 0;

                //2). 如果要求背包恰好装满,
                // 那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,
                // 属于未定义的状态,它们的值就都应该是-∞了。
                volumn[i] = int.MinValue; 
              
            }

            for (int j = 0; j < cost.Length; j++)
            {
                for (int t = v; t >= cost[j]; t--)
                {
                  
                    if (t >= cost[j]) // 容量要大于物体容积,才可能把物体放进去。
                    {
                        volumn[t] = Math.Max(volumn[t], volumn[t - cost[j]] + weight[j]);
                          // f[i][v] = Max{f[i-1][[v], f[i-1][v-c[i]] +w[i]}
                    }                    
                }
            }
        }

 

 数字三角形问题 
给定一个具有N层的数字三角形,从顶至底有多条路径,每一步可沿左斜线向下或沿右斜线向下,路径所经过的数字之和为路径得分,请求出最小路径得分

           2

       6   2

     1   8   4

   1   5   6   8 

     数字三角形

// 利用01背包问题的思路解决数字三角形问题.
        public static void ShortPath(int n)
        {
            //       2
            //    6   2
            //  1   8   4
            //1   5   6   8

            //  数字三角形 

            int[][] array = new int[4][];

            array[0] = new int[] { 2 };
            array[1] = new int[] { 6, 2 };
            array[2] = new int[] { 1, 8, 4 };
            array[3] = new int[] { 1, 5, 6, 8 };

            int[] value = new int[n];

            for (int k = 0; k < n; k++)
            {
                value[k] = array[n - 1][k];
            }

           // 递推关系式:f(i)(j) = min{f(i+1)(j), f(i+1)(j+1)} + array[i][j]

            for (int i = n - 2; i >= 0; i--)
            {
                for (int j = 0; j <= i; j++)
                {
                    value[j] = Math.Min(value[j], value[j + 1]) + array[i][j];

                    //递推关系式:f(i)(j) = min{f(i+1)(j), f(i+1)(j+1)} + array[i][j]
                    // 左下角,(x+1,y),右下角的线(X+1, y+1)
                }
            }
        }

 

 

 

 

posted on 2013-12-24 13:32  higirle  阅读(560)  评论(0编辑  收藏  举报