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();

}

 

posted @ 2015-08-23 14:09  y丫t  阅读(305)  评论(0编辑  收藏  举报