zoukankan      html  css  js  c++  java
  • Dijkstra priority!

    /*
    Dijkstra的算法思想:

    在所有没有访问过的结点中选出dis(s,x)值最小的x

    对从x出发的所有边(x,y),更新

    dis(s,y)=min(dis(s,y),dis(s,x)+dis(x,y))

    */

    下面是热浪的题解:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<algorithm>
    #include<queue>
    #define N 10005
    using namespace std;
    struct sd{
    	int num,len;
    	bool operator < (const sd &x) const
    	{
    		if(x.len<len)
    		{
    			return true;
    		}
    		return false;
    	}
    }lin;
    vector<sd> edge[N];
    priority_queue<sd> q;
    int dis[N];
    bool vis[N];
    int n,m,s,e;
    void init();
    int main()
    {
    	init();
    	return 0;
    }
    void init()
    {
    	scanf("%d%d%d%d",&n,&m,&s,&e);
    	int a;
    	for(int i=1;i<=m;++i)
    	{
    		scanf("%d%d%d",&a,&lin.num,&lin.len);
    		edge[a].push_back(lin);
    		int b=lin.num;
    		lin.num=a;
    		edge[b].push_back(lin);
    	}
    	memset(dis,0x7f7f7f7f,sizeof(dis));
    	dis[s]=0;
    	vis[s]=true;
    	for(int i=edge[s].size()-1;i>=0;--i)//important
    	{//此处有点不熟练,需要多多理解!
    		q.push(edge[s][i]);
    		if(dis[edge[s][i].num]>edge[s][i].len)
    		{
    			dis[edge[s][i].num]=edge[s][i].len;
    		}
    	}
    	
    	
    	for(int i=1;i<n;++i)//very important!!!
    	{
    		sd now;
    		while(!q.empty())
    		{
    			now=q.top();
    			q.pop();
    			if(!vis[now.num])
    			break;
    		}
    		vis[now.num]=true;
    		for(int j=edge[now.num].size()-1;j>=0;--j)
    		{
    			if(!vis[edge[now.num][j].num]&&dis[edge[now.num][j].num]>dis[now.num]+edge[now.num][j].len)
    			{
    				dis[edge[now.num][j].num]=dis[now.num]+edge[now.num][j].len;
    				sd p;
    				p.num=edge[now.num][j].num;
    				p.len=dis[edge[now.num][j].num];
    				q.push(p);
    			}
    		}
    	}
    	printf("%d",dis[e]);
    }
    

    下面我们来做一些简单的讲解:

    首先,我们需要明白Dijsktra的工作原理,他就是,每次找到当前图中已经更新过最短的点(就是将要被加入vis标记的点),对他的四周相连的点进行更新,然后重复这一过程直到找到最终的点。

    详细的算法流程就不再赘述,这里只给一个算法实例(转载)。

    算法实例

    先给出一个无向图

    图片有问题,这里只能上一个地址了:

    无向图

    好像上面的链接还是有问题:

    那就见下面的博客吧!

    dalao的博客(DIjsktra入门(普通版))

    这里我们就主要讲解一下Dijsktra算法相对于普通Dijsktra算法的更新

    下面放一个普通版的Dijsktra:

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    struct sd{
        int len,num;
        sd();
        sd(int a,int b){num=a; len=b;}
        bool operator < (const sd & a) const 
        {
            if(len==a.len) return num<a.num;
            else len>a.len;
        }
    };
    int dis[100005],n,m,s;
    vector<sd> edge[100005];
    void Dijsktra()
    {
        for(int i=1;i<=n;++i)
        {
            dis[i]=2147483647;
        }
        dis[s]=0;
        priority_queue<sd> q;
        q.push(sd(s,dis[s]));
        while(!q.empty())
        {
            sd x=q.top();
            q.pop();
            for(int i=edge[x.num].size()-1;i>=0;--i)
            {
                sd y=edge[x.num][i];
                if(dis[y.num]>x.len+y.len)
                {
                    dis[y.num]=x.len+y.len;
                    q.push(sd(y.num,dis[y.num]));
                }
            }	
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&s);
        int a,b,c;
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&a,&b,&c);
            edge[a].push_back(sd(b,c));
        }
        Dijsktra();
        for(int i=1;i<=n;++i)
        {
            printf("%d ",dis[i]);
        }
        return 0;
    }
    

    主要区别就是,多了一个起点预处理,因为我们要随时保证优先队列中有一些东西,所以说要先把第一个点的信息处理进去。(见第一篇代码important部分)
    然后,后面的其实就一样了,最后还有,当路径被更新后一定不要忘记把更新后的路径扔入priority_queue中

    P.s:一定不要把Dijsktra priorty版和spfa搞混了。SPFA停止条件是当队列为空,而Dijsktra priority和Dijsktra的判停条件是当运行完1~n(n是点数)个点。还有SPFA是队列操作,不是优先队列操作!!!

    特别注意:第一篇代码中标有very important的地方一定是<n不是<=n因为前面预处理第一个点的边的时候,我们相当于已经是循环了一遍了找出最短了!。

    今天2.27我发现了更简单的写法!

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<algorithm>
    #include<queue>
    #define N 10005
    using namespace std;
    struct sd{
        int num,len;
        bool operator < (const sd &x) const
        {
            if(x.len<len)
            {
                return true;
            }
            return false;
        }
    }lin;
    vector<sd> edge[N];
    priority_queue<sd> q;
    int dis[N];
    bool vis[N];
    int n,m,s,e;
    void init();
    int main()
    {
        init();
        return 0;
    }
    void init()
    {
        scanf("%d%d%d%d",&n,&m,&s,&e);
        int a;
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&a,&lin.num,&lin.len);
            edge[a].push_back(lin);
            int b=lin.num;
            lin.num=a;
            edge[b].push_back(lin);
        }
        memset(dis,0x7f7f7f7f,sizeof(dis));
        dis[s]=0;
        //vis[s]=true;
        /*for(int i=edge[s].size()-1;i>=0;--i)//important
        {//此处有点不熟练,需要多多理解!
            q.push(edge[s][i]);
            if(dis[edge[s][i].num]>edge[s][i].len)
            {
                dis[edge[s][i].num]=edge[s][i].len;
            }
        }*/
        sd ti;
        ti.len=0;
        ti.num=s;
        q.push(ti);
        /* 
        for(int i=1;i<n;++i)//very important!!!
        {
            sd now;
            while(!q.empty())
            {
                now=q.top();
                q.pop();
                if(!vis[now.num])
                break;
            }
            vis[now.num]=true;
            for(int j=edge[now.num].size()-1;j>=0;--j)
            {
                if(!vis[edge[now.num][j].num]&&dis[edge[now.num][j].num]>dis[now.num]+edge[now.num][j].len)
                {
                    dis[edge[now.num][j].num]=dis[now.num]+edge[now.num][j].len;
                    sd p;
                    p.num=edge[now.num][j].num;
                    p.len=dis[edge[now.num][j].num];
                    q.push(p);
                }
            }
        }
        */
    while(!q.empty())
    {
    	sd now;    
        now=q.top();
        q.pop();
        if(!vis[now.num])
        {
        	vis[now.num]=true;
        	for(int j=edge[now.num].size()-1;j>=0;--j)
        	{
            	if(!vis[edge[now.num][j].num]&&dis[edge[now.num][j].num]>dis[now.num]+edge[now.num][j].len)
            	{
                	dis[edge[now.num][j].num]=dis[now.num]+edge[now.num][j].len;
                	sd p;
                	p.num=edge[now.num][j].num;
                	p.len=dis[edge[now.num][j].num];
                	q.push(p);
         	   }
        	}
        }
    }
        printf("%d",dis[e]);
    }
    

    缩略版如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<algorithm>
    #include<queue>
    #define N 10005
    using namespace std;
    struct sd{
        int num,len;
        bool operator < (const sd &x) const
        {
            if(x.len<len)
            {
                return true;
            }
            return false;
        }
    }lin;
    vector<sd> edge[N];
    priority_queue<sd> q;
    int dis[N];
    bool vis[N];
    int n,m,s,e;
    void init();
    int main()
    {
        init();
        return 0;
    }
    void init()
    {
        scanf("%d%d%d%d",&n,&m,&s,&e);
        int a;
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&a,&lin.num,&lin.len);
            edge[a].push_back(lin);
            int b=lin.num;
            lin.num=a;
            edge[b].push_back(lin);
        }
        memset(dis,0x7f7f7f7f,sizeof(dis));
        dis[s]=0;
        //vis[s]=true; important! 这句话一定不能写啊!!!! 
        sd ti;
        ti.len=0;
        ti.num=s;
        q.push(ti);
    while(!q.empty())
    {
    	sd now;    
        now=q.top();
        q.pop();
        if(!vis[now.num])
        {
        	vis[now.num]=true;
        	for(int j=edge[now.num].size()-1;j>=0;--j)
        	{
            	if(!vis[edge[now.num][j].num]&&dis[edge[now.num][j].num]>dis[now.num]+edge[now.num][j].len)
            	{
                	dis[edge[now.num][j].num]=dis[now.num]+edge[now.num][j].len;
                	sd p;
                	p.num=edge[now.num][j].num;
                	p.len=dis[edge[now.num][j].num];
                	q.push(p);
         	   }
        	}
        }
    }
        printf("%d",dis[e]);
    }
    

    2018.10.19

    上面的DJ们都写的比较假,下面放上一个可以A掉luogu単源最短路径加强版的代码(上面的都应该A不掉):

    /*
        Name: P4779 【模板】单源最短路径(标准版)
        Copyright:
        Author: Mudrobot
        Date: 2018/10/19 20:57:45
        Description: Graph Theory (The Shortest Path)
    */
    #include<bits/stdc++.h>
    #define gc() getchar()//caution!!!
    #define N 100005
    using namespace std;
    /*inline char gc() {
      static char buf[1<<18],*fs,*ft;
      return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<18,stdin)),fs==ft)?EOF:*fs++;
    }*/
    template<class T>
    inline void read(T &aa) {
      register int k=0,f=1;
      register char c=gc();
      for (;!isdigit(c);c=gc()) if(c=='-')f=-1;
      for (;isdigit(c);c=gc()) k=(k<<3)+(k<<1)+(c-'0');
      aa=k*f;
    }
    template<class T>
    inline void out(T x){if(x>9)out(x/10);putchar(x%10+'0');}
    struct sd{
    	int val,to,next;
    	bool operator < (const sd & njc) const{
    		return val>njc.val;
    	}
    	sd(){}
    	sd(int a,int b,int c){
    		next=a;to=b;val=c;
    	}
    }edge[N*2];
    bool vis[N];
    int n,m,s,qnt,head[N],dis[N];
    void add(int a,int b,int c){
    	edge[++qnt].next=head[a];edge[qnt].to=b;edge[qnt].val=c;head[a]=qnt;
    }
    void Dijkstra(int s){
    	for(int i=1;i<=n;i++) dis[i]=2147483647;
    	priority_queue<sd> q;
    	dis[s]=0;q.push(sd(0,s,dis[s]));
    	while(!q.empty()){
    		sd now=q.top();q.pop();
    		if(vis[now.to]) continue;
    		vis[now.to]=true;
    		for(int i=head[now.to];i;i=edge[i].next){
    			int v=edge[i].to,val=edge[i].val;
    			if(dis[v]>dis[now.to]+val){
    				dis[v]=dis[now.to]+val;
    				q.push(sd(0,v,dis[v]));
    			}
    		}
    	}
    }
    int main()
    {
        //freopen(".in", "r", stdin);freopen(".out", "w", stdout);
    	read(n);read(m);read(s);int a,b,c;
    	for(int i=1;i<=m;++i){
    		read(a);read(b);read(c);
    		add(a,b,c);
    	}
    	Dijkstra(s);
    	for(int i=1;i<=n;++i) out(dis[i]),putchar(' ');
        //fclose(stdin);fclose(stdout);
        return 0;
    }
    /*
    4 6 1
    1 2 2
    2 3 2
    2 4 1
    1 3 5
    3 4 3
    1 4 4
    */
    
    
  • 相关阅读:
    OAuth2.0 基础概述
    Ubuntu安装Gogs服务
    ASP.NET WebAPI 生成帮助文档与使用Swagger服务测试
    ASP.NET MVC 中的路由
    升级Ghost
    搭建Golang开发环境
    TDD并不是看上去的那么美
    .NET Framework 源码查看与调试
    在 ASP.NET MVC 中使用异步控制器
    SpringMVC+FreeMarker+Mybatis 整合
  • 原文地址:https://www.cnblogs.com/mudrobot/p/13328920.html
Copyright © 2011-2022 走看看