图论最短路——dijkstra

下午直接开始dijkstra的堆优化,很简单的这里把书上的原理说一下吧,小心和prim最小生成树的堆优化迷,Dijkstra算法基于贪心思想,它只适用于所有边都是非负数的图。当变长z都是非负数的时候,全局最小值不可能在被其他节点更新,故在第一步中选出的节点x必然满足:dis[x]已经是起点到x的最短路径。我们不断选择全局最小值进行标记和扩展,最终可得到起点s到每个节点的最短路径的长度。

这道题spfa的玄学复杂度被卡只能过两组数据,而m,n的这个范围又不是太友好所以考虑用dijkstra加堆优化,这样就可以过了。。。

make_pari照常如此。将大根堆转成小根堆加个符号即可解决。

#include<iostream>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<map>
using namespace std;
priority_queue<pair<int,int> >q;
const int maxn=200009;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int lin[maxn],ver[maxn],e[maxn],nex[maxn],len=0;
void add(int x,int y,int z)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
    e[len]=z;
}
int n,m,s;
int dis[maxn];
bool vis[maxn];
void dijkstra()
{
    for(int i=1;i<=n;i++)
        dis[i]=2147483647;
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    q.push(make_pair(0,s));
    while(q.size()!=0)
    {
        int x=q.top().second;q.pop();
        if(vis[x]==1)continue;
        vis[x]=1;
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(dis[x]+e[i]<dis[tn])
            {
                dis[tn]=dis[x]+e[i];
                q.push(make_pair(-dis[tn],tn));
            }
        }
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();s=read();
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);
    }
    dijkstra();
    for(int i=1;i<=n;i++)
        printf("%d ",dis[i]);
    return 0;
}
View Code

我本楚狂人,凤歌笑孔丘。

posted @ 2018-09-25 21:12  chdy  阅读(238)  评论(0编辑  收藏  举报