一:格路问题
已知:相邻两点之间的距离(可能不同)。
规则:从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):
注意:填表格的方式。