深入理解动态规划的一系列问题(14)
不知不觉说了这么多问题了,但是很多最优化经典问题没有提到,今天就掀起整个动态规划系列的高潮,来个经典:线性规划问题(Linear Programming)。维基百科里清晰的描写了什么是线性规划。一个简单的描述就是对于一个抽象后的问题,假设目标就是c1x1+c2x2,这里x1和x2都是变量,c1和c2是常量系数,给定一系列约束a11x1+a12x2≤b1,a21x1+a22x2≤b1,a31x1+a32x2≤b3;求最优的x1和x2使得c1x1+c2x2最大化。我们惯性的用线性代数来表示这个问题就是我们要求最大化的cTx,条件是Ax≤b,这里加个限制就是x是正整数(因为往往实际问题中,正数是有意义的)。对于这个问题,其实关键第一步定义状态就很难,这个问题不像以前很多问题一看就是一个图论最短路或者组合优化,我们的思路需要扩展。我们定义一个状态(j,(y1,y2,…ym)),j表示index号也就是变量x的index,而后面的m元组y就表示当前决策下各个约束的值。而在决策阶段,在阶段j做的决策就是从定义域里挑选一个D赋给x(j+1),所以DPFE就变为:f(j,(y1,…,ym))=0 当j=n时,f(j,(y1,…,ym))=max x(j+1)∈D{c(j+1)x(j+1)+f(j+1,(y1-a(1,j+1)x(j+1),…,ym-a(m,j+1)x(j+1))} 当j<n。定义域D表示为D=D(j,(y1,...,ym)) ={0,…,min{y1/a(1,j),…,ym/a(m,j)}},方程的目标就是要求解f(0,(y1,y2,…,ym))。写到这里,花个2-3分钟仔细理解一下这个方程,就能看出,其实又是老套路,线性规划这个看上去复杂的公式也被动态规划的顺序扩展分析方法表示了,递归的选择xi来寻求最值,复杂的约束作为递归的状态不断传递……
具体拿例子说是,假设c=(3,5),b=(4,12,18),并且A是约束矩阵A=[(1,0),(0,2),(3,2)]这里矩阵是行表示法即3行两列矩阵。那么经过上面的迭代求解,可以知道最优的决策组(x1,x2)=(2,6),最大化后的函数值为c1x1+c2x2=3*2+5*6=36。
最后我们附上解题源码:
1: /*
2: * Copyright (C) 2013 changedi
3: *
4: * Licensed under the Apache License, Version 2.0 (the "License");
5: * you may not use this file except in compliance with the License.
6: * You may obtain a copy of the License at
7: *
8: * http://www.apache.org/licenses/LICENSE-2.0
9: *
10: * Unless required by applicable law or agreed to in writing, software
11: * distributed under the License is distributed on an "AS IS" BASIS,
12: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13: * See the License for the specific language governing permissions and
14: * limitations under the License.
15: */
16: package com.jybat.dp;
17:
18: import java.util.HashSet;
19: import java.util.Set;
20:
21: //IntegerLinearProgramming;
22: public class ILP {
23: // objective function coefficients
24: private static int[] c = { 3, 5 };
25: // right hand side of constraints vector
26: private static int[] b = { 4, 12, 18 };
27: // constraint matrix
28: private static int[][] a = { { 1, 0 }, { 0, 2 }, { 3, 2 } };
29: private static int n = c.length;
30: private static int m = b.length;
31: private static final int infty = Integer.MAX_VALUE;
32:
33: private static Set<Integer> calculateDecisionSet(int stage, int y1, int y2,
34: int y3) {
35: Set<Integer> result = new HashSet<Integer>();
36: // maxPossibleChoiceBecauseOfResourceiRestriction, i=1,2,3
37: int mpc1 = infty;
38: int mpc2 = infty;
39: int mpc3 = infty;
40: if (a[0][stage] != 0) {
41: mpc1 = y1 / a[0][stage];
42: }
43: if (a[1][stage] != 0) {
44: mpc2 = y2 / a[1][stage];
45: }
46: if (a[2][stage] != 0) {
47: mpc3 = y3 / a[2][stage];
48: }
49: for (int i = 0; i <= Math.min(mpc1, Math.min(mpc2, mpc3)); i++) {
50: result.add(new Integer(i));
51: }
52: return result;
53: }
54:
55: // here: yi denotes how much of resource i is still available,
56: // (in other words how much slack is still available)
57: public static double f(int stage, int y1, int y2, int y3) {
58: if (stage == n) {
59: return 0.0;
60: }
61: double max = Double.MIN_VALUE;
62: for (int d : calculateDecisionSet(stage, y1, y2, y3)) {
63: double t = c[stage]
64: * d
65: + f(stage + 1, y1 - a[0][stage] * d, y2 - a[1][stage] * d,
66: y3 - a[2][stage] * d);
67: if (t > max)
68: max = t;
69: }
70: return max;
71: }
72:
73: /**
74: * @param args
75: */
76: public static void main(String[] args) {
77: System.out.println(ILP.f(0, b[0], b[1], b[2]));
78: }
79:
80: }