最短路之dijkstra及其堆优化

还有八九十天就NOIP了,我还是要复习一下最短路这类关键的知识点.

原来认为dijkstra堆优化和spfa会一个就行,spfa时间优,码长短.但是近几年spfa不考了.(总是被出题人D)。故意构造数据可以卡到O(k*n^2),有可能跑不过裸dij,所以今天的内容是dijkstra的堆优化,但不会dijkstra也没关系,我现在讲一下.

dijkstra是一个单源最短路.起点固定来求. 我们设起点为S.dis[i]表示由S到达i的最短路径.

那么我们可以从S点开始枚举.运用蓝白点的思维.先把S标志为蓝点表示它已经是dis[i]的最终结果了,显然dis[S]=0;

之后找到一个除了S点以外值最小的点,继续将其标志为蓝点.并把经过点的最短路径修改.手画一张图看着会更清晰些.

   最短路之dijkstra及其堆优化_第1张图片  这是初始场景.

如果我们将原点设为1.dis[1]成为蓝点.  之后dis[2]=2,dis[3]=4,dis[4]=7;

第二轮dis[2]变为最小值,将2变为蓝点.dis[3]=3,dis[5]=4;

第三轮dis[3]最小,把3变为蓝点.dis[4]=4;

但是我们发现一个问题.第一次边权最小时就不再遍历.dijkstra及其堆优化都不能处理此类问题.(边权为负).

 

时间复杂度O(n^2);因为每个点都被修改n次,实际上常数可以小一点.

一道裸例题洛谷P3371,并附上AC代码.如果不够做.题号会在之后公布.(按难度排序)

#include
int head[500001];
int to[500001];
int next[500001];
int val[500001];
int idx;
bool vis[10001];
int dis[10001];
void addedge(int a,int b,int c)
{
    next[++idx]=head[a];
    head[a]=idx;
    to[idx]=b;
    val[idx]=c;
}//链式存储
int main()
{
    int n,m,s,a,b,c;
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        addedge(a,b,c);
    }
    for(int i=1;i<=n;i++)
        dis[i]=2147483647;//因为是最短路,所以要附上最大值.
    dis[s]=0;
    for(int i=1;i<=n;i++)
    {
        int minn=2147483647,t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&dis[j]val[i]+dis[t])
                dis[to[i]]=val[i]+dis[t];//每个点更新最小值
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d ",dis[i]);//输出答案
}

https://neooj.com:8082/oldoj/

VIJOS-P1635 城市连接(JDOJ1594)

USACO 2009 Jan Silver 1.Best Spot(JDOJ2612)

USACO 2009 Open Silver 1.Hide and Seek(JDOJ2641)

[NOIP2001]CAR的旅行路线 T4(JDOJ1288)

USACO 2014 Feb Gold 1.Roadblock(JDOJ2406,2408,2278三倍经验)

下面讲下dijkstra堆优化.堆大家应该都知道,不知道现学一下,用STL之后会很简单明了.

我们维护一个关于边权的小根堆.在找与一个点最小边权时,用堆来维护.直接找到最小值.把那一维n缩减为logE,如果写得好一点可以减为logn

每次我们直接在堆中操作

用priority_queue可以实现这个功能.但是NOIP如果不开O2的话用pbds的堆

我写的是nlogn的,用了priority_queue

// luogu-judger-enable-o2
#include
#include
#include
#include
using namespace std;
int nex[400001];
int to[400001];
int val[400001];
int head[200001];
int f[200001];
int idx,x,y,z;
int inf=2147483647;
bool vis[200001];
struct Point
{
    int number,dis;
    inline bool operator < (const Point &a) const
    {
        return dis>a.dis;
    }
};
priority_queue  q;
void addedge(int a,int b,int c)
{
    nex[++idx]=head[a];
    head[a]=idx;
    to[idx]=b;
    val[idx]=c;
}
int n,m,s;
int main()
{
    Point tmp;
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
    }
    for(int i=1;i<=n;i++)
        f[i]=inf;
    tmp.number=s,tmp.dis=0;
    f[tmp.number]=0;  
    q.push(tmp);
    while(!q.empty())
    {
        int here=q.top().number;
        q.pop();
        if(vis[here])
            continue;
        vis[here]=1;
        for(int j=head[here];j;j=nex[j])
            if(f[to[j]]>val[j]+f[here]&&(!vis[to[j]]))
            {
                f[to[j]]=f[here]+val[j];
                tmp.number=to[j];
                tmp.dis=f[to[j]];
                q.push(tmp);
            }
    }
    for(int i=1;i<=n;i++)
        printf("%d ",f[i]);
}

题号:洛谷P4779

JDOJ2208 短(我发过spfa的题解)

再次给个链接https://neooj.com:8082/oldoj/

USACO  Sweet Butter 香甜的黄油(JDOJ1803)

USACO 2014 Dec Silver 1.Piggyback(JDOJ2911)

JDOJ1070 phoneline(dij很难做,最好用spfa)

好了,今天就到这里了.(其实是博主也没什么会的了)

你可能感兴趣的:(最短路,总结,算法,图论)