zoukankan      html  css  js  c++  java
  • 图论基础

    图论基础

    图的相关概念

    1,图,点和边的集合。
    a,顶点:图中的数据元素称为顶点.
    b,有向图:有方向的图叫有向图.
    c,无向图:没有方向的图叫无线图.
    d,完全图:有n(n-1)/2条边的无向图称为完全图.
    e,有向完全图:具有n(n-1)条弧的有向图称为有向完全图.
    f,稀疏图:有很少条边或弧的图称为稀疏图,反之称为稠密图.
    g,权:与图的边或弧相关的数叫做权(weight).(最小生成树)
    h,度,顶点连边个数

    2,树,连通无回路;无回路的图,森林。
    a,点为n,边为n-1。
    b,最小生成树,kruskal算法(边贪心),prim算法(贪心搜索,bfs,逐步扩展)。

    3,欧拉回路,若图G中存在这样一条路径,恰通过G中每条边一次,则称该路径为欧拉路径;
    若该路径是一个圈,则称为欧拉(Euler)回路。
    七桥问题。(是否是欧拉路或回路可用度来判断)。

    数据结构

    4,计算机存图,邻接矩阵,邻接表,十字链表,向前星。
    a,邻接矩阵,to[i][j],存权值。
    b,邻接表,每个顶点所连边用单链表连起来,存联系节点值,边权值,下一个并列单元。
    (一般直接开stl的vector直接存);
    c,十字链表,用节点的形式保存有值的先关节点。
    d,向前星,x[n],y[n],v[n],s1[n],s2[n],分别为起始节点,结束节点,权值,后俩个为引索。
    e,链式向前星,邻接表类似。

    最短路

    5,最短路,Dijkstra算法,Floyd算法,,bellman-ford算法,SPFA算法
    a,Dijkstra算法,迪杰斯特拉算法(权值非负)
    1).初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
    2).从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
    3).以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
    4).重复步骤b和c直到所有顶点都包含在S中。

          时间复杂度O(n^2);
    

    b,floyd算法,罗伯特·弗洛伊德
    从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查
    Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录
    的便是i到j的最短路径的距离。

           for(k=0;k<n;k++)
           for(i=0;i<n;i++)
           for(j=0;j<n;j++)
           A[i][j]=min(A[i][j],A[i][k]+A[k][j]);
    
        时间复杂度O(n^3)
    

    c,bellman-ford算法,贝尔曼-福特(可有负边,可判断是否有负环)
    下面是主要步骤,方便以后自己理解,代码找板子吧。
    第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
    第二,进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
    第三,遍历途中所有的边(edge(u,v)),判断是否存在这样情况: d(v) > d (u) + w(u,v) 则返回false,表示途中存在从源点可达的权为负的回路。

        时间复杂度O(n*m)
    

    d,SPFA算法,1994年西安交通大学提出,一般认为是bellman-ford的优化。
    主要步骤:
    初始化: d数组全部赋值为INF(无穷大);p数组全部赋值为s(即源点),或者赋值为-1,表示还没有知道前驱然后d[s]=0; 表示源点不用求最短路径,或者说最短路就是0。将源点入队;
         (另外记住在整个算法中有顶点入队了要记得标记vis数组,有顶点出队了记得消除那个标记)

    队列+松弛操作

    读取队头顶点u,并将队头顶点u出队(记得消除标记);将与点u相连的所有点v进行松弛操作,如果能更新估计值(即令d[v]变小),那么就更新,另外,如果点v没有在队列中,那么要将点v入队(记得标记),如果已经在队列中了,那么就不用入队以此循环,直到队空为止就完成了单源最短路的求解。
     

            时间复杂度O(ke),k平均边进栈次数

    受益匪浅

  • 相关阅读:
    58. 最后一个单词的长度
    53. 最大子序和
    50. Pow(x, n)
    35. 搜索插入位置
    28. 实现 strStr()
    leetcode 27. 移除元素
    leetcode 26. 删除排序数组中的重复项
    leetcode 21. 合并两个有序链表
    20. 有效的括号
    多线程案例_循环打印_设计4个线程...
  • 原文地址:https://www.cnblogs.com/refengqingfu/p/7406665.html
Copyright © 2011-2022 走看看