• 最短路


    最短路

    标签(空格分隔): ACM 最短路 图论


    最短路
    Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 28761    Accepted Submission(s): 12444
    
    
    Problem Description
    在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
    
    
    
    Input
    输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
    输入保证至少存在1条商店到赛场的路线。
    
    
    Output
    对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
    
    
    Sample Input
    2 1
    1 2 3
    3 3
    1 2 5
    2 3 5
    3 1 2
    0 0
    
    
    Sample Output
    3
    2

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2544

    求最短路,我是看《挑战程序设计竞赛》里的书学的。
    里面介绍了三种方法: Bellman-Ford、Dijkstra and Floyd
    三者区别也都很明显:

    Bellman-Ford:

    求单源最短路,可以判断有无负权回路(若有,则不存在最短路), 时效性较好,时间复杂度O(VE)。

    Bellman-Ford算法是求解单源最短路径问题的一种算法。

      单源点的最短路径问题是指: 给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。
    
      与Dijkstra算法不同的是,在Bellman-Ford算法中,边的权值可以为负数。       设想从我们可以从图中找到一个环路(即从v出发,经过若干个点之后又回到v)且这个环路中所有边的权值之和为负。那么通过这个环路,环路中任意两点的最短路径就可以无穷小下去。如果不处理这个负环路,程序就会永远运行下去。 而Bellman-Ford算法具有分辨这种负环路的能力。
    

    Dijkstra:

    求单源、无负权的最短路。时效性较好,时间复杂度为O(V*V+E)。 源点可达的话,O(V*lgV+E*lgV)=>O(E*lgV)。 当是稀疏图的情况时,此时E=V*V/lgV,所以算法的时间复杂度可为O(V^2) 。若是斐波那契堆作优先队列的话,算法时间复杂度,则为O(V*lgV + E)。

    Floyd:

    求多源、无负权边的最短路。用矩阵记录图。时效性较差,时间复杂度O(V^3)。 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题。

    Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2)。

    Floyd-Warshall的原理是动态规划: 设Di,j,k为从i到j的只以(1..k)集合中的节点为中间节点的最短路径的长度。 若最短路径经过点k,则Di,j,k = Di,k,k-1 + Dk,j,k-1; 若最短路径不经过点k,则Di,j,k = Di,j,k-1。 因此,Di,j,k = min(Di,k,k-1 + Dk,j,k-1 , Di,j,k-1)。

    在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。 Floyd-Warshall算法的描述如下: for k ← 1 to n do for i ← 1 to n do for j ← 1 to n do if (Di,k + Dk,j < Di,j) then Di,j ← Di,k + Dk,j; 其中Di,j表示由点i到点j的代价,当Di,j为 ∞ 表示两点之间没有任何连接。

    后来,我看Bellman-Ford的队列优化,SPFA(Shortest Path Faster Algorithm )。

    SPFA:

    是Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。(k<

    /**************************************** 
    ***************************************** 
    *        Author:Tree                    * 
    *From :http://blog.csdn.net/lttree      * 
    * Title : 最短路                       * 
    *Source: hdu 2544                       * 
    * Hint : SPFA                           * 
    ***************************************** 
    ****************************************/  
    
    #include <stdio.h>  
    #include <queue>  
    using namespace std;  
    
    #define RANGE 101  
    #define MAX 0x3f3f3f3f  
    int cost[RANGE][RANGE];  
    int d[RANGE];  
    bool used[RANGE];  
    int n,m;  
    
    void spfa( int s )  
    {  
        int i,now;  
        // 初始化  
        for( i=1;i<=n;++i )  
        {  
            d[i]=MAX;  
            used[i]=false;  
        }  
    
        d[s]=0;  
        queue <int> q;  
        q.push(s);  
        used[s] = true;  
    
        while(!q.empty())  
        {  
            now = q.front();  
            q.pop();  
            used[now] = false;  
            for(i = 1; i <= n; i++)  
            {  
                if(d[i] > d[now] + cost[now][i])  
                {  
                    d[i] = d[now] + cost[now][i];  
                    if(used[i] == 0)  
                    {  
                        q.push(i);  
                        used[i] = true;  
                    }  
                }  
            }  
        }  
    }  
    
    int main()  
    {  
        int i,j,A,B,C;  
        while( scanf("%d%d",&n,&m) )  
        {  
            if( !n && !m )  break;  
            // 初始化  
            for( i=1;i<=n;++i )  
                for( j=1;j<=i;++j )  
                    if( i==j )  cost[i][j]=0;  
                    else    cost[i][j]=cost[j][i]=MAX;  
    
            for( i=0;i<m;++i )  
            {  
                scanf("%d%d%d",&A,&B,&C);  
                cost[A][B]=cost[B][A]=C;  
            }  
    
            spfa(1);  
            printf("%d
    ",d[n]);  
        }  
        return 0;  
    }  

    Dijkstra:

    /**************************************** 
    ***************************************** 
    *        Author:Tree                    * 
    *From :http://blog.csdn.net/lttree      * 
    * Title : 最短路                       * 
    *Source: hdu 2544                       * 
    * Hint : Dijkstra                       * 
    ***************************************** 
    ****************************************/  
    
    #include <stdio.h>  
    #define MAX 0x3f3f3f3f  
    #define RANGE 101  
    
    int cost[RANGE][RANGE];  
    int d[RANGE];  
    bool used[RANGE];  
    
    int n,m;  
    int Min( int a,int b )  
    {  
        return a<b?a:b;  
    }  
    
    void Dijkstra( int s )  
    {  
        int i,v,u;  
        for( i=1;i<=n;++i )  
        {  
            used[i]=false;  
            d[i]=cost[1][i];  
        }  
        d[s]=0;  
    
        while( true )  
        {  
            v=-1;  
            for( u=1;u<=n;++u )  
                if( !used[u] && ( v==-1 || d[u]<d[v]) )  
                    v=u;  
            if( v==-1 ) break;  
            used[v]=true;  
    
            for( u=1;u<=n;++u )  
                d[u]=Min( d[u],d[v]+cost[v][u] );  
        }  
    }  
    
    int main()  
    {  
        int A,B,C,i,j;  
    
        while( scanf("%d%d",&n,&m) )  
        {  
            if( !n && !m )  break;  
    
            // 初始化  
            for( i=1;i<=n;++i )  
                for( j=1;j<=i;++j )  
                    if( i==j )  cost[i][j]=0;  
                    else    cost[i][j]=cost[j][i]=MAX;  
    
            for( i=0;i<m;++i )  
            {  
                scanf("%d%d%d",&A,&B,&C);  
                cost[A][B]=cost[B][A]=C;  
            }  
    
            Dijkstra(1);  
            printf("%d
    ",d[n]);  
        }  
        return 0;  
    }  

    Floyd:

    /**************************************** 
    ***************************************** 
    *        Author:Tree                    * 
    *From :http://blog.csdn.net/lttree      * 
    * Title : 最短路                       * 
    *Source: hdu 2544                       * 
    * Hint : Floyd                          * 
    ***************************************** 
    ****************************************/  
    
    #include <stdio.h>  
    #define MAX 0x3f3f3f3f  
    #define RANGE 105  
    
    int d[RANGE][RANGE];  
    int n;  
    
    int Min( int a,int b )  
    {  
        return a<b?a:b;  
    }  
    void warshall_floyd( void )  
    {  
        int i,j,k;  
        for( k=1;k<=n;++k )  
            for( i=1;i<=n;++i )  
                for( j=1;j<=n;++j )  
                    d[i][j]=Min( d[i][j],d[i][k]+d[k][j] );  
    }  
    
    int main()  
    {  
        int m,A,B,C,i,j;  
    
        while( scanf("%d%d",&n,&m) )  
        {  
            if( !n && !m )  break;  
    
            // 初始化  
            for( i=1;i<=n;++i )  
                for( j=1;j<=i;++j )  
                {  
                    if( i==j ) d[i][j]=0;  
                    else    d[i][j]=d[j][i]=MAX;  
                }  
    
            // 输入  
            for( i=0;i<m;++i )  
            {  
                scanf("%d%d%d",&A,&B,&C);  
                d[A][B]=d[B][A]=C;  
            }  
    
            // floyd算法求最短路  
            warshall_floyd();  
            printf("%d
    ",d[1][n]);  
        }  
        return 0;  
    }  

    整体测试代码

    #include<iostream>
    #include<string>
    #include<string.h>
    #include<algorithm>
    #include<iomanip>
    #include<cstdio>
    #include<queue>
    #include<stack> 
    #include<vector>
    #include<functional>  
    #define INF 99999
    using namespace std;
    
    typedef pair<int, int> P;
    
    struct edge {
        int from, to, cost;
    };
    
    int n, m;           //n为顶点数,m为边数
    int a[100][100];
    
    void warshall()
    {
        int b[100][100] = { 0 };
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
                b[i][j] = a[i][j];
        cout << "Floyd-warshall: 
    ";
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                for (int k = 1; k <= n; k++)
                {
                    if (b[j][k] > b[j][i] + b[i][k])
                    {
                        b[j][k] = b[j][i] + b[i][k];
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                cout << b[i][j] << " ";
            }
            cout << endl;
        }
    }
    
    void Dijkstra()
    {
        int dis[100] = { 0 };
        bool book[100] = { 0 };
        int b[100][100] = { 0 };
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
                b[i][j] = a[i][j];
        for (int i = 1; i <= n; i++)
        {
            dis[i] = a[1][i];
        }
        book[1] = 1;
    
        for (int i = 1; i <= n - 1; i++)
        {
            int minv = INF, min = 0;
            for (int i = 1; i <= n; i++)
            {
                if (!book[i] && minv > dis[i])
                {
                    minv = dis[i];                   //在取最小值的过程中可以用堆优化
                    min = i;
                }
            }
            book[min] = 1;
            for (int j = 1; j <= n; j++)
            {
                if (dis[j] > dis[min] + a[min][j])
                {
                    dis[j] = dis[min] + a[min][j];    //用最短的边对其他所有点进行优化
                }
            }
        }
        for (int i = 1; i <= n; i++)
        {
            cout << dis[i] << " ";
        }
        cout << endl;
    }
    
    void Bellman()
    {
        int dis[100] = { 0 };
        int b[100][100] = { 0 };
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
                b[i][j] = a[i][j];
        for (int i = 1; i <= n; i++)
            dis[i] = INF;
        dis[1] = 0;
        /*for (int i = 1; i <= n; i++)
        {
            dis[i] = a[1][i];
        }*/
        for (int i = 1; i <= n - 1; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                for (int k = 1; k <= n; k++)
                {
                    if (dis[k] > dis[j] + a[j][k])
                    {
                        dis[k] = dis[j] + a[j][k];
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++)
        {
            cout << dis[i] << " ";
        }
        cout << endl;
    }
    
    void BellmanQueue()
    {
        int dis[100] = { 0 };
        int b[100][100] = { 0 };
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
                b[i][j] = a[i][j];
        for (int i = 1; i <= n; i++)
            dis[i] = INF;
        dis[1] = 0;
        queue<int> que;
        bool book[100] = { 0 };
        que.push(1);
        book[1] = 1;
        while (que.size())
        {
            int k = que.front();
            que.pop();
            for (int i = 1; i <= n; i++)
            {
                if (dis[i] > dis[k] + b[k][i])
                {
                    dis[i] = dis[k] + b[k][i];
                    if (!book[i])
                    {
                        que.push(i);
                        book[i] = 1;
                    }
                }
            }
            book[k] = 0;
        }
        for (int i = 1; i <= n; i++)
        {
            cout << dis[i] << " ";
        }
        cout << endl;
    }
    
    void warshall2()
    {
        vector<edge> G[100];
        int n, m;
        cin >> n >> m;
        for (int i = 0; i < m; i++)
        {
            int p;
            edge q;
            cin >> p >> q.to >> q.cost;
            G[p].push_back(q);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int k = 1; k <= n; k++)
            {
                for (int j = 0; j < G[k].size(); j++)
                {
                    edge e = G[k][j];
                }
            }
        }
        cout << "不会
    ";
    }
    
    void Dijkstra2()
    {
        vector<edge> G[100];
        int n, m;
        cin >> n >> m;
        int dis[100] = { 0 };
        fill(dis, dis + 100, INF);
        dis[1] = 0;
        for (int i = 0; i < m; i++)
        {
            int p;
            edge q;
            cin >> p >> q.to >> q.cost;
            G[p].push_back(q);
        }
        priority_queue<P, vector<P>, greater<P> >que;
        que.push(P(0, 1));
        while (que.size())
        {
            P p= que.top(); que.pop();
            for (int i = 0; i < G[p.second].size(); i++)
            {
                edge e = G[p.second][i];
                if (dis[e.to] > dis[p.second] + e.cost)
                {
                    dis[e.to] = dis[p.second] + e.cost;
                    que.push(P(dis[e.to], e.to));
                }
            }
        }
        for (int i = 1; i <= n; i++)
        {
            cout << dis[i] << " ";
        }
        cout << endl;
    }
    
    void Bellman2()
    {
        edge G[100];
        int n, m;
        cin >> n >> m;
        int dis[100] = { 0 };
        fill(dis, dis + 100, INF);
        dis[1] = 0;
        for (int i = 0; i < m; i++)
        {
            cin >> G[i].from >> G[i].to >> G[i].cost;
        }
        for (int i = 1; i <= n - 1; i++)
        {
            for (int j = 0; j < m; j++)
            {
                dis[G[j].to] = min(dis[G[j].to], dis[G[j].from] + G[j].cost);
            }
        }
        for (int i = 1; i <= n; i++)
        {
            cout << dis[i] << " ";
        }
        cout << endl;
    }
    
    int main()
    {
        cin >> n >> m;
        for(int i=0;i<=n;i++)
            for (int j = 0; j <= n; j++)
            {
                if (i == j) a[i][j] = 0;
                else a[i][j] = INF;
            }
        for (int i = 1; i <= m; i++)
        {
            int p, q, t;
            cin >> p >> q >> t;
            a[p][q] = t;
        }
        cout << "邻接矩阵:
    ";
        cout << "1:Floyd-warshall    2:Dijkstra    3:Bellman-Ford    4:Bellman队列优化(SPFA)
    ";
        cout << "邻接表
    ";
        cout << "5:Floyd-warshall    6:Dijkstra(堆优化)   7:Bellman-Ford
    ";
        int t;
        while (cin >> t)
        {
            if (t == 1)
            {
                warshall();
            }
            else if (t == 2)
            {
                cout << "Dijkstra:
    ";
                Dijkstra();
            }
            else if (t == 3)
            {
                cout << "Bellman-Ford:
    ";
                Bellman();
            }
            else if (t == 4)
            {
                cout << "Bellman队列优化:
    ";
                BellmanQueue();
            }
            else if (t == 5)
            {
                cout << "Floyd-warshall(邻接表):
    ";
                warshall2();
            }
            else if (t == 6)
            {
                cout << "Dijkstra(堆优化) 
    ";
                Dijkstra2();
            }
            else if (t == 7)
            {
                cout << "Bellman-Ford:
    ";
                Bellman2();
            }
        }
    }
    
    
    Fighting~
  • 相关阅读:
    ASCII 32个控制字符含义
    MFC中获取指定打印机的打印队列的方法
    某品牌led报文信息分析
    SQL Server 企业版没有 Management Studio管理工具 无法安装工作站组件 的解决方法(无需卸载重装)
    xla文件修改办法
    关于ALILIB
    编译器如何根据头文件来找到相应实现的cpp文件?
    C#调用C++接口提示找不到指定的模块解决方法,本机正常
    DataGridView中实现右击选中当前行功能,并通过ContextMenuStrip获取当前行
    C#递归获取文件列表
  • 原文地址:https://www.cnblogs.com/Archger/p/8451658.html
Copyright © 2020-2023  润新知