算法录 之 拓扑排序和欧拉路径。

1:

  问题:

  对于一个DAG(有向无环图),求点的排序,使得排在后面的点不能通过一条路径到前面的点。

  如图,他的其中一个拓扑排序是 1,2,3,4,5,但是1,2,5,3,4不行,因为3能到5。

 

  求解算法:

  可以看出如果某个点有入边,也就是有其他的点能够到这个点,那么显然这个点不能被放在开头。所以就需要先找到一个入度为0的点放在开头,然后删掉这个点和这个点连接的所有的边,然后对剩下的图递归求解就OK了。

  然后实现方法类似BFS,把所有入度为0的点加入队列,然后每次取出队首的点放入答案数组中,然后删掉所有从这个点出发的边后,把新产生的入度为0的点加入。

  伪代码如下:

 1 vector <int> Rank() {
 2     Queue que;
 3     vector <int> ans;
 4 
 5     for(int i=1;i<=N;++i)
 6         if(degree(i)==0) que.push(i);
 7 
 8     while(!que.empty()) {
 9         int t=que.first();
10         que.pop();
11 
12         ans.push_back(t);
13         
14         for(所有从t出发的边e) {
15             --degree(e.to);        // 删除这条边并且让这条边到达的那个点的入度减一。
16             if(degree(e.to)==0) que.push(e.to);
17         }
18     }
19 
20     return ans;
21 }

  复杂度的话,因为每个点最多遍历一次,每个点的每条边也是。

  所以复杂度是 N+M (M是边数)。

 

2:

  问题:

  求一个无向图的一条欧拉路?也就是是否可以一笔画完?

 

  先判断图是否存在欧拉路,不存在直接返回。根据欧拉的定理:如果一个无向图有三个或者三个以上的点的度数是奇数,就没有欧拉路。

  先找到degree为奇数的一个点(不存在的话就任意点)作为开始点,进行DFS,每次走过一条边之后就删除这条边。然后当某个点无路可走的时候,把这个点加入答案数组。

  最后答案数组反向就是答案。

 

  伪代码如下:

 1 vector <int> ans;
 2 
 3 void dfs(int u) {
 4     if(u没有路可以继续下去) ans.push_back(u);
 5     else {
 6         for(e 是 u 出发的边) {
 7             delete e;
 8             dfs(e.to);
 9         }
10     }
11 }
12 
13 void getEuler() {
14     int start;
15     for(start=1;start<=N;++start)
16         if(degree(start)%2==1)
17             break;
18     if(start==N+1) start=1;
19 
20     dfs(start);
21     ans.reverse();        // ans反向。
22 }

 

  例图如下:

 

                          从1开始dfs,找到1-2的边,删除,dfs 点2      然后找到边2-3,删除,dfs 点3

  

    然后找到边1-3,删除,dfs 点1。      这时dfs 点1无路可走,把1加入ans。然后回溯到3,  然后找到边4-5,删除,dfs 点5。

                        找到边3-4,删除,dfs 点4。

  然后找到边5-3,删除,dfs 点3        然后3无路可走,加入ans,回溯到5,然后5无路可走,加入ans,回溯到4,然后4无路可走,加入ans,回溯到3,然后3无

                       路可走,加入ans,回溯到2,然后2无路可走,加入ans,回溯到1,然后1无路可走,加入ans。

 

  这时ans数组是 1,3,5,4,3,2,1。

  倒序的话就是一条欧拉路。

  至于正确性的证明,严密的证明不会,但是如果一个点边很少的话一定要尽量往后被访问,不然进去就出不来了。所以这算是半个贪心策略,嗯。

posted @ 2015-12-22 16:27  WhyWhy。  阅读(1177)  评论(0编辑  收藏  举报