基本思想:
动态规划(Dynamic programming,DP),通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。
步骤:
1. 找出最优解的性质,并刻画其结构特征
2. 递归定义最优值
3. 以自底向上的方式计算出最优值
4. 根据计算最优值得到的信息,构造一个最优解
重要性质:
1. 最优子结构
2. 重叠子问题
范例:
1. 最短路径
#include<iostream>
#include<string.h>
using namespace std;
#define LENGTH 5
/*
matrix 图
minPath 临时数组
visit 是否访问
LENGTH 点数
MinDistance(v) 出发点到v的最短距离
Fk(u) 表示从Sk中的点u到终点的距离
Sk 表示某点的子边集合
*/
int matrix[LENGTH][LENGTH] = {
0,10,0,30,100,
0,0,50,0,0,
0,0,0,0,10,
0,0,20,0,60,
0,0,0,0,0,
};
int minPath[LENGTH];
bool visit[LENGTH];
/* 递归深度搜索 */
int MinDistance(int v)
{
if(minPath[v] > 0) return minPath[v];
if(v == LENGTH -1) return 0;
int min = 1000,t,j;
for(int i = 0;i < LENGTH;i++)
{
if(matrix[v][i] > 0 && visit[i] == false)
{
visit[i] = true;
/* 动态方程式 MinDistance(u) = min{w(u,v) + MinDistance(v)} */
t = MinDistance(i) + matrix[v][i];
visit[i] = false;
if(min > t)
{
min = t;
j = i;
}
}
}
minPath[v] = min;
return minPath[v];
}
/* 迭代搜索 */
int MinDistanceEx()
{
minPath[0] = 1000;
for(int i = 0;i < LENGTH;i++)
{
for(int j = 0;j < LENGTH;j++)
{
if(matrix[i][j] > 0)
{
/* 状态方程式 Fk(u) = min{w(u,v) + Fk+1(v)} */
if(i > 0)
{
/* 刷新自己到出发点最短距离 */
if(minPath[j] > minPath[i] + matrix[i][j])
{
minPath[j] = minPath[i] + matrix[i][j];
}
/* 刷新其他结点到出发点最短距离 */
for(int k = 0;k < LENGTH;k++)
{
if(k != j && matrix[j][k] > 0 && minPath[k] > minPath[j] + matrix[j][k])
{
minPath[k] = minPath[j] + matrix[j][k];
}
}
}
else
{
minPath[j] = matrix[i][j];
}
}
}
}
return minPath[LENGTH-1];
}
int main(void)
{
for(int i = 0;i < LENGTH;i++)
{
trace[i] = 0;
minPath[i] = 1000;
visit[i] = false;
}
//int minD = MinDistance(0);
int minD = MinDistanceEx();
std::cout<<"minD:"<<minD<<std::endl;
return 0;
}
2 最长公共子序列
#include <stdio.h>
#include <iostream>
#include <string.h>
#define MAXLEN 100
void LCSLength(char *x, char *y, int m, int n, int c[][MAXLEN], int b[][MAXLEN])
{
int i, j;
for(i = 0; i <= m; i++)
c[i][0] = 0;
for(j = 1; j <= n; j++)
c[0][j] = 0;
for(i = 1; i<= m; i++)
{
for(j = 1; j <= n; j++)
{
if(x[i-1] == y[j-1])
{
c[i][j] = c[i-1][j-1] + 1;
b[i][j] = 0;
}
else if(c[i-1][j] >= c[i][j-1])
{
c[i][j] = c[i-1][j];
b[i][j] = 1;
}
else
{
c[i][j] = c[i][j-1];
b[i][j] = -1;
}
}
}
}
void PrintLCS(int b[][MAXLEN], char *x, int i, int j)
{
if(i == 0 || j == 0)
return;
if(b[i][j] == 0)
{
PrintLCS(b, x, i-1, j-1);
printf("%c ", x[i-1]);
}
else if(b[i][j] == 1)
PrintLCS(b, x, i-1, j);
else
PrintLCS(b, x, i, j-1);
}
int main(int argc, char **argv)
{
char x[MAXLEN] = "ABCBDAB";
char y[MAXLEN] = "BDCABAB";
int b[MAXLEN][MAXLEN];
int c[MAXLEN][MAXLEN];
int m, n;
m = strlen(x);
n = strlen(y);
LCSLength(x, y, m, n, c, b);
PrintLCS(b, x, m, n);
return 0;
}