HDU2544最短路(边权为正,djkstra和floyd做法)

第一种做法: djkstra做法

#include<iostream>
#include<cstring>
using namespace std;
const int maxn=105;
const int inf=0x3f3f3f;
int mapp[maxn][maxn];
int vis[maxn];//区分结点在S中还是V-S中
int dis[maxn];//最短路
int n,m,a,b,c;
void init()
{
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            mapp[i][j]=inf;
    memset(vis,0,sizeof(vis));
}
void djkstra(int x,int n)//以x为源点,以n为终点的最短路
{
    for(int i=1; i<=n; i++)
        dis[i]=mapp[x][i];
    vis[x]=1;//S中初始的点只有x结点
    for(int i=1; i<=n; i++)
    {
        int minx=inf;
        int p;
        for(int j=1; j<=n; j++)
            if(!vis[j]&&dis[j]<minx)
            {
                p=j;
                minx=dis[j];
            }//将V-S中的最短路径求出,用dis[p]表示
        vis[p]=1;//使p点进入S集合
        for(int j=1;j<=n;j++)
            if(!vis[j]&&dis[j]>dis[p]+mapp[p][j])
            dis[j]=dis[p]+mapp[p][j];
    }
}
int main()
{
    while(cin>>n>>m)
    {
        if(!m&&!n)break;
        init();
        for(int i=0; i<m; i++)
        {
            cin>>a>>b>>c;
            mapp[a][b]=mapp[b][a]=c;
        }
        djkstra(1,n);
        cout<<dis[n]<<endl;
    }
    return 0;
}

第二种做法:弗洛伊德做法

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=105;
const int inf=0x3f3f3f;
int dis[maxn][maxn];
int n,m,p,q,t;
void init()
{
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            dis[i][j]=inf;
}
void floyd()
{
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
int main()
{
    while(cin>>n>>m)
    {
        if(n==0&&m==0)
            break;
        init();
        for(int i=0; i<m; i++)
        {
            cin>>p>>q>>t;
            dis[p][q]=dis[q][p]=t;
        }
        floyd();
        cout<<dis[1][n]<<endl;
        //已经求得任意两点间的最短路径
    }
    return 0;
}

总结:djkstra算法的求解过程:

对于网络N=(V,E)中的顶点V划分为两部分:

第一部分S:表示已经求出最短路径的顶点集合,初始时只包含源点v0

第二部分V-S:没有求出最短路径的顶点集合,初始时为集合V-{v0}

算法的操作内容:按照v0到每个顶点最短路径长度递增的顺序,将集合V-S中的顶点逐个加入S中。

在操作的过程中,总保证v0到S中各顶点的长度始终不大于v0到V-S中各顶点的路径长度。

下面证明这种求解方式的正确性:

假设S是已经求得最短路径顶点的集合,假设下一条我们要求的最短路径终点是x

可以证明:下一条最短路径只有下面两种情况而不会出现第三种情况:

1.边(v0,x)

2.v0经过S集合中的顶点最后到达x的路径

我们可以用反证法证明:假设出现第三种情况:v0经若干顶点到达x的最短路径上有一个顶点v在集合V-S中:

这说明存在一个V-S集合中的顶点v使v0-v的路径长度小于v0-x的路径长度,这是不可能的。因为算法是按照

路径长度递增的顺序产生最短路径的,所以长度比v0-x小的路径都已经产生,且顶点v必定在集合S中。

算法的正确性证明完毕。

猜你喜欢

转载自blog.csdn.net/qq_41658955/article/details/81480796