zoukankan      html  css  js  c++  java
  • Graph Summer2015 WEEK 1

    林瀚老师的算法课(小学期讲图论)讲得很棒 :)

    WEEK 1

    1、 G(V,E)  表示方法

     临接矩阵   

    在Warshall算法里喜欢用这个

     临界表      

    vector (可变长,我最熟悉这种,方便), 链表(学数据结构我喜欢把G和T(tree)的连接点放在这儿,

     边集合      

    刚刚想到以前做过这种题,用边集合吧是DP好像。。记一下。遇见了再说。

     离散课蔡国扬老师说有8种表示方法

    2、建图

    有些问题是不能直接建图的,要边解问题边建立图。这两个问题是以解的状态作为节点,边的建立是两个状态之间关系决定的。例子八数码 , 农夫过河

    八数码 

    3*3格子里一个空的,手机上的拼图游戏。一个状态就是从(1,1)...(3,3)的排列比如123456780(0代表空格子).总共有9!种状态,有些状态可以转换,比如012345678和102345678,把第一个的1向左移动. 如果AB可转换,则AB间有一条边。问题转换成一个很大的图,找一条从初始点到终点的路。之前用A*算法解这问题。

    农夫过河 

    农夫有菜羊狼,狼吃羊吃菜. 求过河方案. 如上每只羊、狼、菜、农夫有在河的0岸和1岸两种状态。如0000是初始状态,1111是结束状态。总共[0000,1111]种状态,每种状态为安全/不安全,如0011狼吃羊。过河的方案就是招路。    

    总的来说就是不一样的编码方式,之前把一个点、地方等元素看作是点,边是之间的关系,现在把解看作是点,解之间的关系看作是边

    3、BFS

      -无权树最短路

        隔壁女生说像Dijstra,Dijstra就是BFS思路写的。或者说在Dikstra中,如果全部路径为1则就是BFS

      - 复杂度分析(Why is the complexity of BFS O(V+E) instead of O(V*E)?)

        曾经觉得算复杂度就是看循环,用队列模拟BFS

    while(!q.empty()){                 //  每个点进一次队
        u = q.top();
        q.pop()
        for each v satisfy (u,v)      //   每条边检查一次 
            q.push();
    }

     

       while()最多V次,for最多E,于是O(V*E), 真相是...

       (v1+v1 的临接边)+(v2+v2的临接边)+...+(vn+vn 的临接边)

         = (v1+v2+...+vn) + (v1临接边+v2临接边+..+vn临接边)   // 注意每条边检查一次

         = V+E

        误会产生是因为第两个循环的变量的增加依赖于第一个循环的变量。

    4、DFS

    看到DFS树的时候觉得啊哈。挺熟练的。。一段时间后。。啧啧。。那些(1,18)数对(pre,post)是什么鬼,之前没见过。联想树遍历pre()、post(),找规律,应该是第一次和最后一次访问结点的,在递归函数开头结尾可以求,怎么求,放个计数器cnt就可以了嘛,哈!那这个有什么用呢?恩,可以判断圈,好像2-连通的是什么也有用到,怎么用的嘞。。(林翰)DFS树有四种边。分类耶,我喜欢,mark下听课。哇塞!听了下面的感觉好神奇好兴奋。所以说我下次要认真听课。林翰讲的简单的东西可能会蹦出好玩的。 :)  求中排....看不见课件。废话没了..

    研究对象:DFS树,带有pre和post值,pre pst 就是begin end

    // 

    eg: G = [ (1, [2, 4]), (2, [3]), (3, []),

           (4, [6]), (5, [8]), (6, [5, 8]),
    (7, []), (8, []), (9, []) ]

    pre post实现

    void DFS(u,timer/cnt)
    {
        timer ++  ;
        pre[u] = timer;         // if post[v] exist ,Cross edge
        for (u,v) 
            if not visit v         // 如果之前已经访问了,就是回边。
                DFS(v)
        timer ++ ;
        post[u] = timer;               
        
    }

    四种边:  

    实边:树边  Tree Edge    (u,v)
    虚边:回边  Forward Edge (当前节点,祖先)   形成环
         潜向边  Back Edge   (当前节点,后代)
         横跨边  Cross Edge  (当前节点,祖先别的后代)

    设用‘[u’表示pre[u],‘]u’表示post[u] 

    对于节点u,v 

    1、u,v都在DFS树中 ((v))

    - 如果u是v祖先,则pre[u]<pre[v], post[u]>post[v],再加上pre[u]<post[u], pre[v]<post[v],得pre[u]<pre[v]<post[v]<post[u],即 [u, [v, ]v, ]v。

    - if (u,v) is Tree Edge,then pre[v]=pre[u]+1,因为访问完u下一个就是v所以(u,v)才会出现在DFS树中,反之不成立,反例当访问完A的一颗子树最后一个节点u,开始访问下一棵子树的根节点v。

    - (u,v) is Forward Edge,v是u祖先

    2、u,v不都在DFS树中

    - Back Edge : (v(u,u)v) v是u的某个后代,那么在pre[u]出现后,递归肯定会访问到v_pre[v],然后离开v_post[v]后才会继续u的其他分支,接着离开u_post[u]

    - Cross Edge : [u ]u [v ]v == (u)(v)  在数轴上,u v 的[pre,post]两个区间不交叉!!! 显然,找一个uv共同祖先p,p先访问到u_pre[u],因为v在另一颗子树上,所以离开u_post[u]后才会访问另一棵子树,pre[v],post[v]才会出现。就是想象数轴是一条时间轴,跟着算法走、我被惊艳到了、、之前没有想过居然可以用区间的形式来判断。。

    作用

    Back Edge 判断有无环

    post 排序可用于拓扑排序, 可以用反证法/演绎法证明。

      - 如果post[u]<post[v]出现了,意味着u还没访问完的话v不能访问,赤裸裸的拓扑排序 。。

      - 可画图看出/ 老师将DFS树按post排成线性的,可以看到u如果在v左边,即post[u]<post[v],则没有回边(v,u)。

     // 果然思路被打断之后有点忘记要写什么了、、、

    5、拓扑排序

    1- 度序列,不断找一个度为0的更新遍历

    for all v
        if(degree[v]==0) q.push(v)
    while(!q.empty()){
         u = q.top(); q.pop();
         // update degree and check 
         for all v (u,v)
             if(--degree[v]) q.push(v)   
    }

    2- 用post值,DFS,O(N+E)

    timer = 0;
    for all v in V
        set pre = post = 0.
    for each node v that post[v]= 0; 
         DFS(v). 
    sort(post)

            

    各种实现方法复杂度
    DFS
    queue // priority_queue

    UPDATE : 

    今天买了课本《算法概论》(注释版),机械工业出版社,英文的,注解是中文的,375页。
    如果是清华大学出版的,就是中文的。
    之前写的内容和书中3.1~3.3节相同。

    摘要:
    p90 3.3 DFS

    Property :
      In a dag,every edge leads to a vertex with aq lower post number.

    每一条边都指向post值更低的。

    togetther,acyclicity linearity and the absence of back edge during DFS is the same thing

    在DFS中,无环 线性(拓扑) 和无back edge 是相同的。

      -----------------------------------------------------------------------

    UPDATE 2 

    今天上课和同学聊天突然想到。

    4种边,只有对于有向如来说才有意义,对于无向图来说,没多大必要,back edge 和 forward edge是同时存在的;  如果(v->u)是cross edge则u->v一定存在,那么v在DFS树中应在u的孩子当中

    const int notgo = 0;
    const int go1 = 1;
    const int go2 = 2;
    void DFS(int u)
    {
        if(go[u]==notgo) go[i] = go1;
            else if (go[u]==go1) go[i] = go2;
        find adjanced v
        if(go1) // back edge, cycle
            else if(go2) // cross edg e
                else DFS();
    
    }
  • 相关阅读:
    经典数组排序方法------快速排序法
    经典数组排序方法------选择排序法,冒泡排序法
    两个非常好的bootstrap模板,外送大话设计模式!
    商场促销-策略模式(和简单工厂模式很像的哇) C#
    代码无错就是优?简单工厂模式 C#
    大话设计模式(C#)
    马加爵遗书 VS 药家鑫遗书
    GIT 常用命令
    Random快速产生相同随机数的原因及解决方案
    JSON WEB TOKEN,简单谈谈TOKEN的使用及在C#中的实现
  • 原文地址:https://www.cnblogs.com/tinyork/p/4750036.html
Copyright © 2011-2022 走看看