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) } } }
做个快乐的自己。