zoukankan      html  css  js  c++  java
  • 最短路相关模板、总结

    1.

    Dijkstra模板

     自己写一遍才知道可能犯的错误,囧。

    HDU2544大水题一枚。 http://acm.hdu.edu.cn/showproblem.php?pid=2544

    //1.注意INF的取值,不仅仅是最大边长度  2.注意W[i][j]的清空
    void Dijk()
    {
        memset(v,0,sizeof(v));
        for(int i=1;i<=n;i++)
            d[i]=(i==1)?0:INF;
        for(int i=1;i<=n;i++)
        {
            int x,m=INF;
            for(int j=1;j<=n;j++)
            {
                if(!v[j]&&d[j]<m)
                  x=j,m=d[j];  //x:当前选出的最小点
            }
            v[x]=1;
            for(int j=1;j<=n;j++)
            {
                if(d[j]>(d[x]+w[x][j]))
                    d[j]=d[x]+w[x][j];
            }
        }
    }

    边(x,y)上的松弛操作

    if(d[j]>(d[x]+w[x][j]))
        {
               d[j]=d[x]+w[x][j];
               fa[j]=x;
         }


    附POJ2387   http://poj.org/problem?id=2387

     : Dijk不适合有重边的情况,(显然),然后需要自己判一下,囧。


    或者只读入w[a][b]=c即可,但是要当a>b时,swap(a,b);

    具体同临接表。自己发现,具体证明算导应该有吧。

    临接表做法,适用与稀疏图,先给每条边编号,next[e]表示e的下一条边

    总感觉自己写的模板没问题,可至今未过题快哭了,先放这。 

    void adj()
    {
        memset(visit,0,sizeof(visit));
        memset(next,-1,sizeof(next));
        for(int i=1;i<=n;i++)
           first[i]=-1,d[i]=(i==1)?0:INF;
        for(int i=1;i<=m;i++)
        {
           scanf("%d%d%d",&u[i],&v[i],&w[i]);//别忘交换。
           if(u[i]>v[i]) swap(u[i],v[i]);
           next[i]=first[u[i]];
           first[u[i]]=i;
        }
        for(int i=1;i<=n;i++) //这地方要循环n次
        {
            int x,temp=INF;
            for(int j=1;j<=n;j++)
                if(!visit[j]&&d[j]<temp) x=j,temp=d[j];
            visit[x]=1;
            for(int e=first[x];e!=-1;e=next[e])
            {
                if(d[v[e]]>(d[x]+w[e]))
                    d[v[e]]=d[x]+w[e];
            }
        }
    }


    Dijkstra不能计算负权的原因:

    dijkstra由于是贪心的,每次都找一个距源点最近的点(dmin),然后将该距离定为这个点到源点的最短路径(d[i]<--dmin);但如果存在负权边,那就有可能先通过并不是距源点最近的一个次优点(dmin'),再通过这个负权边L(L<0),使得路径之和更小(dmin'+L<dmin),则dmin'+L成为最短路径,并不是dmin,这样dijkstra就被囧掉了。
    比如n=3,邻接矩阵:
    0,3,4
    3,0,-2
    4,-2,0
    用dijkstra求得d[1,2]=3,事实上d[1,2]=2,就是通过了1-3-2使得路径减小。

    2、Floyd算法

    //先初始化d[i][i]=0,其他为INF
        for(int k=0;k<n;k++)
            for(int i=0;i<n;i++)
              for(int j=0;j<n;j++)
                {
                    if(d[i][j]>(d[i][k]+d[k][j]))
                        d[i][j]=d[i][k]+d[k][j];
                }
    1.注意重边,选最小的边
    
    2.注意如果自身到自身返回0
    
    3.注意双向边   //这三条不管是用那个算法都注意一下。

       Floyd算法边权可正可负,不适合大量顶点。

       有向图的传递闭包:HDU1181


    3、Bellman-ford算法  时间复杂度O(n*m)

    For i:=1 to |V|-1 do //v为顶点数
    For 每条边(u,v)∈E do  //对每条边进行遍历
      Relax(u,v,w);
    For每条边(u,v)∈E do
      If dis[u]+w<dis[v] Then Exit(False)

    可以判断是否存在 负权环


    o(∩∩)o...哈哈,偶终于明白了。。

    Bellman-ford也不能直接照着LRJ的代码敲,自己得加两种情况,就是考虑是有向图还是无向图。(每种最短路算法都要这样。奋斗


    妹的啊,Bellman-ford是判断负权环的,存在负权环可以来回走,负权边就不可以来回走了?

  • 相关阅读:
    呵呵
    数据类型转换方法
    工业设计三原则
    C#实现的根据年月日计算星期几的函数
    网页设计的12种颜色
    SqlParameter 存储过程
    HTTP 状态响应码
    Android获取屏幕高度和宽度
    Android屏幕自适应解决方案
    Nodejs学习笔记nodejs的安装
  • 原文地址:https://www.cnblogs.com/pangblog/p/3294078.html
Copyright © 2011-2022 走看看