zoukankan      html  css  js  c++  java
  • 题解:2018级算法第五次上机 C5-图2

    题目描述:

    样例:

    实现解释:

    所有结点对最短路径的板子题

    知识点:

    寻找所有结点对最短路径,动态规划

    坑点:

    无坑,注意建边即可

     

    使用的算法为floyd算法

    按照程序顺序解释如下:

    首先建图,以邻接矩阵形式,初始化矩阵内容:对i==j的设为权值0,其他的设为INF(正无穷的大小取决于题目),以便后续计算时能区分自身和不可达结点。然后依据输入按照edge[u][v] = w的形式连点即可。

    运行floyd算法

    动态规划思想展现:最优子结构,状态转移方程

    以下图为例:(来源网络)

     

    上图中1号到5号的最短路径序列<1,2,4,5>,其子序列<1,2,4>也是最短路径。以dp[k][i][j]表示以点1到k之间的点为媒介时,从i到j的最短路径。那么为了进行状态转移,需要和之前的dp建立关系,则对dp[k-1][i][j]可有以下的两种情况:

      1.dp[k][i][j]的最短路不经过k

      dp[k][i][j]=dp[k-1][i][j]

      2.dp[k][i][j]的最短路经过k

      dp[k][i][j]=dp[k-1][i][k]+dp[k-1][k][j]

    则有状态转移方程

    dp[k][i][j] = min(dp[k-1][i][j], dp[k-1][i][k]+dp[k-1][k][j])(k,i,j∈[1,n])

    边界条件即dp[0][i][j] = edge[i][j]

    又从状态转移方程可看出,k只和k-1有关,因此可进行维度优化:

      dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j])(k,i,j∈[1,n])每次只需自身和另一种情况对比便可达到同样的效果。

      则从分析可知,程序内容其实和矩阵链乘十分类似,初始化dp数组(dp[i][j]=edge[i][j],边界条件)后,三层循环便可得到结果。

      具体可见代码。

    完整代码:

    #include <iostream>
    #include <string>   
    #include <stdio.h>   
    using namespace std;
    #define MAX 210
    #define INF 99999
    int n,e;
    int edges[MAX][MAX]; 
    long long dp[MAX][MAX];
    int path[MAX][MAX];
    void createGraph()
    {
        int u,v,w;
        cin >> n >> e;
        for(int i = 0; i<n; i++)
        {
            for(int j = 0; j<n; j++)
            {
                if(i == j) edges[i][j] = 0;
                else edges[i][j] = INF;
            }
        }
        for(int i = 0; i<e; i++)
        {
            cin >> u >> v >> w;
            edges[u-1][v-1] = w;
        }
    }
    void getPath()
    {
        int from,to,length = -1;
        for(int i = 0;i<n;i++)
        {
            for(int j = 0;j<n;j++)
            {
                if(dp[i][j] != INF)
                {
                    if(dp[i][j]>length)
                    {
                        from = i+1;
                        to = j+1;
                        length = dp[i][j];
                    }
                }
            }
        }
        cout << from << ' ' << to << '
    ';
    }
     
    void floyd()
    {
        for(int i = 0;i<n;i++)
        {
            for(int j = 0;j<n;j++)
            {
                dp[i][j] = edges[i][j];
            }
        }
        for(int k = 0;k<n;k++)
        {
            for(int i = 0;i<n;i++)
            {
                for(int j = 0;j<n;j++)
                {
                    //抛去维度,直接计算 
                    if(dp[i][j] > dp[i][k]+dp[k][j])
                    {
                        dp[i][j] = dp[i][k]+dp[k][j];
                        path[i][j] = k;
                    }
                }
            }
        }
        getPath();
    }
    int main()
    {
        int t;
        cin >> t;
        while(t--)
        {
            createGraph();
            floyd();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    RESTful API设计指南
    Ubuntu16.04 安装openssl
    shell while循环
    linux awk
    vim与shell切换
    shell for循环
    css 固定宽度,自动换行
    php-fpm 与 cgi
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/usr/local/mysql/tmp/mysql.sock'
    linux ps 命令参数详解
  • 原文地址:https://www.cnblogs.com/doUlikewyx/p/11906557.html
Copyright © 2011-2022 走看看