zoukankan      html  css  js  c++  java
  • 算法录 之 拓扑排序和欧拉路径。

    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。

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

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

  • 相关阅读:
    301重定向的代码
    小问题,小细节要注意(string类型转换为bool类型)
    关于添加网站适配的问题解决
    this.Page.Request.ServerVariables
    将一个字段的两个数据分开读取
    使用distinct出现的一个问题
    什么是集合是只读的?
    编辑完这一条数据如何继续转入下一条数据(快速编辑)
    系统信息相关命令
    用户权限相关命令
  • 原文地址:https://www.cnblogs.com/whywhy/p/5067085.html
Copyright © 2011-2022 走看看