Vj作业拓扑排序经典理解题Ordering Tasks 1Kahn算法;2基于DFS的算法。

Posted llbingg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vj作业拓扑排序经典理解题Ordering Tasks 1Kahn算法;2基于DFS的算法。相关的知识,希望对你有一定的参考价值。

2018-02-13

链接   https://cn.vjudge.net/contest/211129#problem/D

John has n tasks to do. Unfortunately, the tasks are not independent and the execution of one task is only possible if other tasks have already been executed.
Input
The input will consist of several instances of the problem. Each instance begins with a line containing two integers, 1 ≤ n ≤ 100 and m. n is the number of tasks (numbered from 1 to n) and m is the number of direct precedence relations between tasks. After this, there will be m lines with two integers i and j, representing the fact that task i must be executed before task j. An instance with n = m = 0 will ?nish the input.
Output
For each instance, print a line with n integers representing the tasks in a possible order of execution.
Sample Input
5 4 1 2 2 3 1 3 1 5 0 0
Sample Output
1 4 2 5 3

感想:

  刚开始学拓扑排序,学了下面两种方法去做这道经典的简单题:1、Kahn算法;2、基于DFS的算法(用得比较多)。说实话,完全看懂花了一个晚上一个早上,实现基本上也是跟人家的实现没差的,虽然很不喜欢这么不独立地做题,但是事实水平还不到,也是刚学嘛...什么时候做什么事,学习有方法,怎么学有效率,还在摸索...据说两者复杂度一样都是O(V+E),之前对复杂度的计算有很多误解,现在开始遇到一种算法就自己算一下,慢慢理解进去,也能培养做题前计算复杂度的习惯,同时方便以后做题。学得差不多了会把所有算法的复杂度自己整理一遍。

Kahn代码:

     /*拓扑排序*/ 
#include<cstdio>               
#include<cstring>  
#include<vector>  
#include<queue>                   // 
using namespace std;  
const int N = 105;  
int n,m,son[N],topoSort[N],t;    //son是用来储存入度的 toposort顾名思义就是存放题目要求的序列 
char O[2*N];  
vector<int>G[N];                 //vector关联顶点   G[N]接下来是用来断弧的 
  
void init(){  
    for(int i=1; i<=n; ++i){  
        G[i].clear();  
    }  
    memset(son, 0, sizeof(son));  
}  
  
int main(){  
    int u,v;  
    while(scanf("%d%d",&n,&m)&&n+m){  
        init();  
        for(int i=0; i<m; ++i){                   //这些地方i的初始值都不是随意的,要小心,老是出错
            scanf("%d%d",&u,&v);   
            G[u].push_back(v);  
            ++son[v];  
        }  
        int num=n;  
        queue<int>q;                                // 先进先出,类似排队那样,先进去的元素最先出去的一种数据结构。
        for(int i=1; i<=n; ++i){  
            if(!son[i]) q.push(i);               //将0入度的点推入栈 
        }  
        int pos=0;              
        while(!q.empty()){                     // empty    判断容器是否为空,如果为空则返回true 这里就是为非空的时候执行while 
            int t=q.front();  
            q.pop();  
            topoSort[pos++] = t;  
            for(int v=0; v<G[t].size(); ++v)       //断弧  注意写法 
                if(--son[G[t][v]]==0)               
                    q.push(G[t][v]);               //kahn的复杂度为O(n+m)  其实是n的线性阶加上这里去弧的次数 (也就是看最里面的循环次数,这里就是m)
        }  
        for(int i=0; i<pos; ++i){  
            if(!i)printf("%d",topoSort[i]);  
            else printf(" %d",topoSort[i]);  
        }  
        printf("\n");  
    }  
    return 0;  
}  

基于DFS的算法(运用递归,要判断是否为DAG) 

#include<string.h>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector> 
#include<queue>
using namespace std;
int n,m;
int vis[105];                 //标记
int topo[105]; 
int G[105][105];
int t;
bool dfs(int u)
{
    vis[u]=-1;                //表示正在访问 1表示已经访问过 0表示没有访问过
    for(int v=1;v<=n;v++)
    {
        if(G[u][v])      
        {
            if(vis[v]==-1) return false;         // 如果存在有向环,失败退出
            if(!vis[v]&&!dfs(v)) return false; //!vis[v]是为了检验这个点是否已经被访问过 访问过就不dfs 不然会重复存入 实际效果就是省略一个if啦,想了好久唉 
        }                                        //以后可以这样写 
    }
    vis[u]=1; topo[--t]=u;
    return true;
}
bool toposort()
{   
    t=n;
    memset(vis,0,sizeof(vis));
    for(int u=1;u<=n;u++)
    {
        if(!vis[u]&&!dfs(u)) return false;//只有vis[u]是0时 进行dfs 而且存在环的时候才返回false   vis[u]=1说明已经访问过 就不dfs了 避免改变vis的值
        
    }
    return true;
} 
int main()
{  
   int a,b;
   while(~scanf("%d%d",&n,&m)&&m+n) // 注意输入那里的结束条件不能是 n&&m,因为m可能是0
   {
         memset(G,0,sizeof(G));
         for(int i=1;i<=m;i++)
       {
         scanf("%d%d",&a,&b);
         G[a][b]=1; 
       } 
          if(toposort())
       {
             for(int i=0;i<n;i++)
             if(!i) printf("%d",topo[i]);
          else   printf(" %d",topo[i]);
          printf("\n");      
          }          
   }    
} 

 

以上是关于Vj作业拓扑排序经典理解题Ordering Tasks 1Kahn算法;2基于DFS的算法。的主要内容,如果未能解决你的问题,请参考以下文章

[拓扑排序]Ordering Tasks UVA - 10305

UVA10305 Ordering Tasks

Ordering Tasks 拓扑排序

D - Ordering Tasks (拓扑排序)

UVa 10305 - Ordering Tasks (拓扑排序裸题)

UVA - 10305 Ordering Tasks(拓扑排序)