关于动态规划的几个算法

一:格路问题                                                                             

已知:相邻两点之间的距离(可能不同)。

规则:从O点出发,只能向上向右,计算到达E点的最短距离。

方法1:枚举法

m个X,n个Y进行排列

(m + n)!/(m!*n!)  = Cm+nm

加法:Cm+nm*(m+n-1)

比较:Cm+nm – 1

方法2:动态规划

4, 5                               //代表m+1,n+1

1,-1   2, -1  1,-1   4,-1    -1,-1     //最右边点为终点E

4, 11  3, 27  2, 9   7,6     -1, 2

1, 15  3, 19  2,59  7,16    -1, 18

7,10   3,20  2,31  7,12    -1, 47    //最左边点为起点O

注:第1行数据为逗号隔开的两个整数值,分别代表m+1,n+1 即格路的列数与行数;每行数据代表格路上的一行数据,每组数据代表相应的点向右,向上的距离(均为整数)。

数据结构:

public struct TPoint<T>                 //二维数据表中每个结点的数据结构
{
public T nUp, nRight; //此点到邻近上一个结点、右一个结点的距离
public T nShortest; //最短路径长
public Direction nFrom; //最短路径上前一个结点的来源
}

public enum Direction
{
No = 0, //0:没有最短路径 1: 左, 2:右.
Left,
Down
}

核心算法:

    public class GeLuSolution
{
private TPoint<int>[][] Points;
private int m; //行数 4
private int n; //列数 5
public GeLuSolution() { }

public void Calculate() //动态规划方法求解此问题
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i == 0 && j == 0) // 初始化原点数据
{
Points[i][j].nShortest = 0; //最短路径为 0
Points[i][j].nFrom = Direction.No; //没有节点来源
}
else if (i == 0 & j > 0) // 点在Y轴上
{
//点(j,0) 的最短距离:(j-1,0)的最短距离 + d[(j-1,0),(j,0)]
Points[0][j].nShortest = Points[0][j - 1].nShortest + Points[0][j - 1].nRight;
Points[0][j].nFrom = Direction.Left;
}
else if (i > 0 && j == 0)
{
//点(0,i) 的最短距离:(0,i-1)的最短距离 + d[(0,i-1),(0,i)]
Points[i][0].nShortest = Points[i - 1][0].nShortest + Points[i - 1][0].nUp;
Points[i][0].nFrom = Direction.Down;
}
else
{
//点(j,i) 的最短距离:Min(s1, s2)
int s1 = Points[i][j - 1].nShortest + Points[i][j - 1].nRight;
int s2 = Points[i - 1][j].nShortest + Points[i - 1][j].nUp;
if (s1 < s2)
{
Points[i][j].nShortest = s1;
Points[i][j].nFrom = Direction.Left;
}
else
{
Points[i][j].nShortest = s2;
Points[i][j].nFrom = Direction.Down;
}
}
}
}
}

二:矩阵连乘问题:矩阵连乘乘法最小次数?

设n个矩阵连乘:A[0]*A[1]*…*A[n-1]

A[i] 是list[i] * list[i+1]的矩阵   //list记录的是所有矩阵的秩

Reuslt[i][j] = (A[i]...A[k])(A[k+1]…A[j])

                = Min{左最小 + 右最小 + list[i]*list[k+1]*list[j+1]}

问题即求:Result[0][n-1]!

数据结构:

struct TA
{
public int M;// 最小乘法次数
public int K;// 在K出断开
}

 

class MatrixMultiplication
{
public TA[][] result; //中间结果记录
public List<int> list; //矩阵的秩列表
private int n; // 矩阵个数

public MatrixMultiplication(List<int> _list)
{
if (_list == null || _list.Count == 0)
{
throw new ArgumentNullException();
}

list = _list;
Initialize();
}

private void Initialize()
{
n = list.Count - 1; //注意减 1
result = new TA[n][];
for (int i = 0; i < n; i++) //初始化
{
result[i] = new TA[n];
result[i][i].M = 0;
result[i][i].K = i;
}
}

public void Caculate()
{
for (int r = 1; r < n; r++)
{
//循环计算 result[i][i + r]的值:result[0][r],result[1][r + 1],...,result[n - r -1][n - 1]
for (int i = 0; i < n - r; i++)
{
#region 默认在i处断开

//计算乘法次数
int m = result[i][i].M + result[i + 1][i + r].M + list[i] * list[i + 1] * list[i + r + 1];

//记录断开的地方
int mk = i;
                #endregion
//针对某个result[i][i + r],求其最小值。分别在i+1,i+2,...,i + r -1处断开。
for (int k = i + 1; k < i + r; k++)
{
int them = result[i][k].M + result[k + 1][i + r].M + list[i] * list[k + 1] * list[i + r + 1];
if (them < m)
{
m = them;
mk = k;
}
}
result[i][i + r].M = m;
result[i][i + r].K = mk;
}
}
}
}

 

//调用:

MatrixMultiplication test = new MatrixMultiplication(new List<int>() { 3, 4, 3, 12, 6, 14 });
test.Caculate();

//输出结果(最小为558):

注意:填表格的方式。


原文地址:https://www.cnblogs.com/lujiao_cs/p/2279488.html