最短路(SPFA、Dijkstra、Floyd、Bellman-Ford)

题目链接:   最短路


Dijkstra(迪杰斯特拉)算法 
解决无负权边的带权有向图或无向图的单源最短路问题

用邻接表,不优化,时间复杂度O(V2+E) 
Dijkstra+堆的时间复杂度 o(ElgV) 
用斐波那契堆可以做到O(VlogV+E)  

若要输出路径,则设置prev数组记录每个节点的前趋点,在d[i] 更新时更新prev[i]

#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
const int inf=0x3f3f3f3f;
struct node{
    int to,val;
    node(){}
    node(int a,int b){to=a;val=b;}
    bool operator<(const node &xx)const{
        return xx.val<val;
    }
};
vector<node> mp[N];
int n,m;
int dis[N];
void dijkstra(int s)
{
    memset(dis,inf,sizeof dis);
    priority_queue<node> q;
    q.push(node(s,0));dis[s]=0;
    while(!q.empty())
    {
        int from=q.top().to;  q.pop();
        for(int i=0;i<mp[from].size();i++)
        {
            int to=mp[from][i].to;
            int val=mp[from][i].val;
            if(dis[to]>dis[from]+val)
                q.push(node(to,dis[to]=dis[from]+val));
        }
    }
    printf("%d\n",dis[n]);
}
int main()
{
    int i,j,t,tt=0;
    while(~scanf("%d%d",&n,&m),n|m)
    {
        memset(mp,0,sizeof mp);
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(node(b,c));
            mp[b].push_back(node(a,c));
        }
        dijkstra(1);
    }
}

经典例题:poj 3159


Bellman-Ford(贝尔曼-福特)算法 
解决含负权边的带权有向图的单源最短路径问题  
不能处理带负权边的无向图(因可以来回走一条负权边)  
限制条件:  要求图中不能包含权值总和为负值回路(负权值回路

假设图的顶点个数为n,边的个数为e  
使用邻接表存储图,复杂度O(n*e)  
使用邻接矩阵存储图,复杂度为O(n3); 

Bellman-Ford算法不一定要循环n-1次,n为顶点个数  
只要在某次循环过程中,考虑每条边后,源点到所有顶点的最短路径 长度都没有变,那么Bellman-Ford算法就可以提前结束了 
第n次可以判断是否有负权值回路

(本题是把边扩展成2*e个,变成”有向图”求解) 

#include <cstdio>
const int max_v = 110;
const int max_e = 10010;
const int INF = 1000000000;
int e,v;
struct edge {
    int from,to,cost;
};
int d[max_v];
edge eg[max_e*2];
int main()
{
    while(scanf("%d%d",&v,&e) && v) {
        //边扩展到1-2e范围
        for(int i = 0 ; i < max_v ; i ++) d[i] = INF;
        for(int i = 1 ; i <= e ; i ++) {
            scanf("%d%d%d",&eg[i].from,&eg[i].to,&eg[i].cost);
            eg[i+e].from = eg[i].to;
            eg[i+e].to = eg[i].from;
            eg[i+e].cost = eg[i].cost;
        }
        d[1] = 0;
        while(true) {
            bool flag = false;
            for(int i = 1 ; i <= 2*e ; i ++) {
                if(d[eg[i].from] != INF && d[eg[i].from]+eg[i].cost < d[eg[i].to]) {
                    d[eg[i].to] = d[eg[i].from]+eg[i].cost;
                    flag = true;
                }
            }
            if(!flag) break;
        }
        printf("%d\n",d[v]);
    }
    return 0;
}

经典例题:poj 1860 3259 2240

SPFA(队列优化))算法
快速求解含负权边的带权有向图的单源最短路径问题 
是Bellman-Ford算法的改进版,利用队列动态更新dist[]

在平均情况下,SPFA算法的期望时间复杂度为O(E)

#include<bits/stdc++.h>
#include<stdlib.h>
#include<stdio.h>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e3;
const int inf=0x3f3f3f3f;
struct node{
    int to,val;
    node(){}
    node(int a,int b){to=a;val=b;}
};
vector<node> mp[N];
int n,m;
int dis[N];
bool used[N];
bool spfa(int s)
{
    memset(dis,inf,sizeof dis);
    memset(used,0,sizeof used);
    queue<int> q;
    q.push(s);dis[s]=0;used[s]=1;
    while(!q.empty())
    {
        int from=q.front();q.pop();
        used[from]=0;
        for(int i=0;i<mp[from].size();i++)
        {
            int to=mp[from][i].to;
            int val=mp[from][i].val;
            if(dis[to]>dis[from]+val)
            {
                dis[to]=dis[from]+val;
                if(!used[to])
                    used[to]=1,q.push(to);
            }
        }
    }
    return 0;
}
int main()
{
    int i,j,t,tt=0;
    while(~scanf("%d%d",&n,&m),n|m)
    {
        memset(mp,0,sizeof mp);
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(node(b,c));
            mp[b].push_back(node(a,c));
        }
        spfa(1);
        printf("%d\n",dis[n]);
    }
}

经典例题:poj 2387 3256

http://poj.org/problem?id=3259

//#include<bits/stdc++.h>
#include<stdlib.h>
#include<stdio.h>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N=500+7;
const int inf=0x3f3f3f3f;
int mp[N][N];
int n,m,k;
int dis[N];
bool used[N];
int in[N];
bool spfa(int s)
{
    memset(dis,inf,sizeof dis);
    memset(used,0,sizeof used);
    memset(in,0,sizeof in);
    queue<int> q;
    q.push(s);
    dis[s]=0;used[s]=1;in[s]=1;
    while(!q.empty())
    {
        int from=q.front();q.pop();
        used[from]=0;
        for(int i=1;i<=n;i++)
        {
            int to=i;
            int val=mp[from][i];
            if(dis[to]>dis[from]+val)
            {
                dis[to]=dis[from]+val;
                if(!used[to])
                {
                    in[to]++;
                    if(in[to]==n) return 1;//存在一点入队次数大于总顶点数
                    used[to]=1,q.push(to);
                }
            }
        }
        if(dis[s]<0) return 1;//优化
    }
    return 0;
}
int main()
{
    int i,j,t,tt=0;
    scanf("%d",&t);
    while(t--)
    {
        memset(mp,inf,sizeof mp);
        scanf("%d%d%d",&n,&m,&k);
        int a,b,c;
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a][b]=mp[b][a]=min(mp[a][b],c);
        }
        while(k--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a][b]=min(mp[a][b],-c);
        }
        if(spfa(1)) printf("YES\n");
        else        printf("NO\n");
    }
}


Floyd(弗洛伊德)算法
用于求每一对顶点之间的最短路径。有向图,无向图均可,也可以有负权边 
时间复杂度O(n3)
空间复杂度O(n2)

#include<bits/stdc++.h>
using namespace std;
const int N=1e2+7;
const int inf=0x7fffffff;
int f[N][N];
int main()
{
    int i,j,k,m,n,t,tt=0;
    while(scanf("%d%d",&n,&m),n|m)
    {
        int a,b,c;
        memset(f,0x3f3f3f3f,sizeof(f));
        for(i=0;i<m;i++) cin>>a>>b>>c,f[a][b]=c,f[b][a]=c;

        for(k=1;k<=n;k++)
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
        cout<<f[1][n]<<endl;
    }
    return 0;
}

经典例题:poj 1125


http://lx.lanqiao.cn/problem.page?gpid=T22

解题报告:http://blog.csdn.net/yyii1111/article/details/18905125

spfa

#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pall;
vector<pall> mp[N];
int dis[N];
bool vis[N];
void spfa(int s)
{
    memset(dis,inf,sizeof dis);dis[s]=0;
    memset(vis,0,sizeof vis);  vis[s]=1;
    queue<int> q;              q.push(s);
    while(!q.empty())
    {
        s=q.front();q.pop();
        vis[s]=0;
        for(int i=0;i<mp[s].size();i++)
        {
            int e=mp[s][i].first;
            int val=mp[s][i].second;
            if(dis[e]>dis[s]+val)
            {
                dis[e]=dis[s]+val;
                if(!vis[e]) vis[e]=1,q.push(e);
            }
        }
    }
}
int main()
{
    int i,j,t,tt=0,s,x,y,n,m;
    int a,b,c;
    while(~scanf("%d%d%d%d",&n,&x,&y,&s))
    {
        memset(mp,0,sizeof mp);
        while(x--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
            mp[b].push_back(make_pair(a,c));
        }
        while(y--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
        }
        spfa(s);
        for(int i=1;i<=n;i++) if(dis[i]!=inf) printf("%d\n",dis[i]);
        else printf("NO PATH\n");
    }

spfa优化

#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pall;
vector<pall> mp[N];
int dis[N];
bool vis[N];
void spfa(int s)
{
    memset(dis,inf,sizeof dis);dis[s]=0;
    memset(vis,0,sizeof vis);  vis[s]=1;
    deque<int> q;              q.push_back(s);
    while(!q.empty())
    {
        s=q.front();q.pop_front();
        vis[s]=0;
        for(int i=0;i<mp[s].size();i++)
        {
            int e=mp[s][i].first;
            int val=mp[s][i].second;
            if(dis[e]>dis[s]+val)
            {
                dis[e]=dis[s]+val;
                if(!vis[e])
                {
                    vis[e]=1;
                    if(!q.empty())
                    {
                        if(dis[e]>dis[q.front()])
                            q.push_back(e);
                        else q.push_front(e);
                    }
                    else q.push_back(e);
                }
            }
        }
    }
}
int main()
{
    int i,j,t,tt=0,s,x,y,n,m;
    int a,b,c;
    while(~scanf("%d%d%d%d",&n,&x,&y,&s))
    {
        memset(mp,0,sizeof mp);
        while(x--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
            mp[b].push_back(make_pair(a,c));
        }
        while(y--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
        }
        spfa(s);
        for(int i=1;i<=n;i++) if(dis[i]!=inf) printf("%d\n",dis[i]);
        else printf("NO PATH\n");
    }
}


dijkstra

#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
struct node{
    int to,val;
    node(){}
    node(int a,int b){to=a;val=b;}
    bool operator<(const node &xx)const{
        return xx.val<val;
    }
};
vector<node> mp[N];
int dis[N];
void dijkstra(int s)
{
    memset(dis,inf,sizeof dis);dis[s]=0;
    priority_queue<node> q;q.push(node(s,0));
    while(!q.empty())
    {
        s=q.top().to;  q.pop();
        for(int i=0;i<mp[s].size();i++)
        {
            int e=mp[s][i].to;
            int val=mp[s][i].val;
            if(dis[e]>dis[s]+val)
                q.push(node(e,dis[e]=dis[s]+val));
        }
    }
}
int main()
{
    int i,j,t,tt=0,s,x,y,n,m;
    int a,b,c;
    while(~scanf("%d%d%d%d",&n,&x,&y,&s))
    {
        memset(mp,0,sizeof mp);
        while(x--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(node(b,c));
            mp[b].push_back(node(a,c));
        }
        while(y--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(node(b,c));
        }
        dijkstra(s);
        for(int i=1;i<=n;i++)
            if(dis[i]!=inf) printf("%d\n",dis[i]);
        else printf("NO PATH\n");
    }
}
有问题
#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pall;
vector<pall> mp[N];
int dis[N];
void dijkstra(int s)
{
    memset(dis,inf,sizeof dis);dis[s]=0;
    priority_queue<pall> q;    q.push(make_pair(s,0));
    while(!q.empty())
    {
        s=q.top().first;  q.pop();
        for(int i=0;i<mp[s].size();i++)
        {
            int e=mp[s][i].first;
            int val=mp[s][i].second;
            if(dis[e]>dis[s]+val)
                q.push(make_pair(e,dis[e]=dis[s]+val));
        }
    }
}
int main()
{
    int i,j,t,tt=0,s,x,y,n,m;
    int a,b,c;
    while(~scanf("%d%d%d%d",&n,&x,&y,&s))
    {
        memset(mp,0,sizeof mp);
        while(x--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
            mp[b].push_back(make_pair(a,c));
        }
        while(y--)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
        }
        dijkstra(s);
        for(int i=1;i<=n;i++) if(dis[i]!=inf) printf("%d\n",dis[i]);
        else printf("NO PATH\n");
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值