• 关于动态规划的几个算法


    一:格路问题                                                                             

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

    规则:从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):

    注意:填表格的方式。


  • 相关阅读:
    前缀和
    B. Ilya and Queries
    BZOJ1652 [Usaco2006 Feb]Treats for the Cows
    NOIP2014提高组 酱油记
    NOIP初赛 BLESS ALL!
    BZOJ1096 [ZJOI2007]仓库建设
    BZOJ1036 [ZJOI2008]树的统计Count
    BZOJ1030 [JSOI2007]文本生成器
    BZOJ2749 [HAOI2012]外星人
    BZOJ1093 [ZJOI2007]最大半连通子图
  • 原文地址:https://www.cnblogs.com/lujiao_cs/p/2279488.html
Copyright © 2020-2023  润新知