最短路

最短路

标签(空格分隔): 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\n",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\n",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\n",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: \n";
    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 << "不会\n";
}

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 << "邻接矩阵:\n";
    cout << "1:Floyd-warshall    2:Dijkstra    3:Bellman-Ford    4:Bellman队列优化(SPFA)\n";
    cout << "邻接表\n";
    cout << "5:Floyd-warshall    6:Dijkstra(堆优化)   7:Bellman-Ford\n";
    int t;
    while (cin >> t)
    {
        if (t == 1)
        {
            warshall();
        }
        else if (t == 2)
        {
            cout << "Dijkstra:\n";
            Dijkstra();
        }
        else if (t == 3)
        {
            cout << "Bellman-Ford:\n";
            Bellman();
        }
        else if (t == 4)
        {
            cout << "Bellman队列优化:\n";
            BellmanQueue();
        }
        else if (t == 5)
        {
            cout << "Floyd-warshall(邻接表):\n";
            warshall2();
        }
        else if (t == 6)
        {
            cout << "Dijkstra(堆优化) \n";
            Dijkstra2();
        }
        else if (t == 7)
        {
            cout << "Bellman-Ford:\n";
            Bellman2();
        }
    }
}

posted @ 2017-06-24 21:18  Archger  阅读(202)  评论(0编辑  收藏  举报