最短路模板总结

以HDU 2544为例   将所有最短路的模板敲一遍  

1、Dijkstra

思想:以边贪心+松弛   

适用范围:单源最短路径、边权不能为负

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x7ffffff
int n,m;
int mpt[105][105];
int vis[105];
int dist[105];
void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)mpt[i][j]=0;
            else mpt[i][j]=INF;
        }
    }
}
void dij()
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        dist[i]=mpt[1][i];
    vis[1]=1;
    dist[1]=0;
    int v=1;
    for(int i=1;i<n;i++)
    {
        int mink=INF;
        for(int j=1;j<=n;j++)
        {
            if(vis[j]==0&&mink>dist[j])
            {
                v=j;
                mink=dist[j];
            }
        }
        if(mink==INF)break;
        vis[v]=1;
        for(int j=1;j<=n;j++)
        {
            if(vis[j]==0&&dist[j]>dist[v]+mpt[v][j])
                dist[j]=dist[v]+mpt[v][j];
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        init();
        int a,b,c;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(c<mpt[a][b])
            {
                mpt[a][b]=c;
                mpt[b][a]=c;
            }
        }
        dij();
        printf("%d\n",dist[n]);
    }
    return 0;
}

2、Floyd

思想:动态规划

适用范围:稠密图、边权可正可负

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x7ffffff
int n,m;
int mpt[105][105];
void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)mpt[i][j]=0;
            else mpt[i][j]=INF;
        }
    }
}
void floyd()
{
    for(int i=1;i<=n;i++)//中间节点
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=1;k<=n;k++)
            {
                if(mpt[j][k]>mpt[j][i]+mpt[i][k])
                    mpt[j][k]=mpt[j][i]+mpt[i][k];
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        init();
        int a,b,c;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(c<mpt[a][b])
            {
                mpt[a][b]=c;
                mpt[b][a]=c;
            }
        }
        floyd();
        printf("%d\n",mpt[1][n]);
    }
    return 0;
}
3、Bellman_Ford

思想:贪心松弛、Bellman-Ford算法的迭代松弛操作,实际上就是按顶点距离s的层次,逐层生成这棵最短路径树的过程

适用范围:普遍适用、但效率很低

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x7ffffff
int n,m;
struct node
{
    int u,v,len;
}edge[10005];
int dist[105];
bool Bellman_Ford()
{
    for(int i=1;i<=n;i++)
        dist[i]=INF;
    dist[1]=0;
    for(int i=1;i<n;i++)
    {
        for(int j=1;j<=m*2;j++)
        {
            if(dist[edge[j].v] > dist[edge[j].u] + edge[j].len) //松弛(顺序一定不能反~)
            {
                dist[edge[j].v] = dist[edge[j].u] + edge[j].len;
            }
        }
    }
    bool flag=true;
    //判断是否有负环路
    for(int i=1;i<=m*2;i++)
    {
        if(dist[edge[i].v]>dist[edge[i].u]+edge[i].len)
        {
            flag=false;
            break;
        }
    }
    return flag;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        int a,b,c;
        for(int i=1;i<=m*2;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            edge[i].u=a;
            edge[i].v=b;
            edge[i++].len=c;
            edge[i].u=b;
            edge[i].v=a;
            edge[i].len=c;
        }
        if(Bellman_Ford())
            printf("%d\n",dist[n]);
        else
            printf("-1\n");
    }
    return 0;
}

4、SPFA

思想:Bellman-Ford算法的优化、动态逼近法、用队列来保存待优化的节点、由无权图的BFS转化而来

适用范围:如果某个点进入队列次数超过N次则存在负环(SPFA无法处理带负环的图)/一般用邻接表来存储图

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define INF 0x7ffffff
int n,m;
struct node
{
    int to,next,val;
}edge[10005];
int head[105];
int dist[105];
int vis[105];
int k;
void add(int x,int y,int val)
{
    edge[k].to=y;
    edge[k].val=val;
    edge[k].next=head[x];
    head[x]=k++;
}
void SPFA()
{
    queue<int> q;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        dist[i]=INF;
    dist[1]=0;
    vis[1]=1;
    q.push(1);
    while(!q.empty())
    {

        int now=q.front();
        q.pop();
        vis[now]=0;
        for(int i=head[now];i!=-1;i=edge[i].next)
        {
            int s=edge[i].to;
            if(dist[s]>dist[now]+edge[i].val)
            {
                dist[s]=dist[now]+edge[i].val;
                if(vis[s]==0)
                {
                    vis[s]=1;
                    q.push(s);
                }
            }
        }
    }
}
void init()
{
    k=0;
    memset(head,-1,sizeof(head));
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        init();
        int a,b,c;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        SPFA();
        printf("%d\n",dist[n]);
    }
    return 0;
}

差分约束系统:

一般不等式可以转化为图论的建图、最后求单源最长路径或最短路径



你可能感兴趣的:(最短路总结)