UVa 10305 Ordering Tasks(拓扑排序)

来源:互联网 发布:软件测试员要求 编辑:程序博客网 时间:2024/06/18 17:47

原题

 Ordering Tasks

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 finish 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

题意

假设有n个结点,还有m个二元组(i,j),分别表示结点i在j之前。完成对它的拓扑排序,输出任意一种排序方式。

涉及知识及算法

拓扑排序
把每个变量看成一个点,“小于”关系看成有向边,则得到了一个有向图。这样,我们的 任务实际上是把一个图的所有结点排序,使得每一条有向边(u, v)对应的u都排在v的前面。在 图论中,这个问题称为拓扑排序(topological sort)。
不难发现:如果图中存在有向环,则不存在拓扑排序,反之则存在。不包含有向环的有 向图称为有向无环图(Directed Acyclic Graph,DAG)。可以借助DFS完成拓扑排序:在访问完一个结点之后把它加到当前拓扑序的首部(想一想,为什么不是尾部)。
这里用到了一个c数组,c[u]=0表示从来没有访问过(从来没有调用过dfs(u));c[u]=1表 示已经访问过,并且还递归访问过它的所有子孙(即dfs(u)曾被调用过,并已返回);c[u]=1表示正在访问(即递归调用dfs(u)正在栈帧中,尚未返回)。
可以用DFS求出有向无环图(DAG)的拓扑排序。如果排序失败,说明该 有向图存在有向环,不是DAG。

代码

#include <iostream>#include <queue>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>using namespace std;const int maxn=101;//存储每个结点的状态int c[maxn];//存储排完序的结点int topo[maxn],n,t;//存储结点之间的关系(有无通路)bool G[maxn][maxn];bool dfs(int u){    c[u]=-1;      //访问标志:正在访问    for(int v=1;v<=n;v++)      //寻找所有后继    {        if(G[u][v])            //若有路        {            if(c[v]<0)        //如果正在防问            {                return false; //存在有向环,失败退出            }            else if(!c[v]&&!dfs(v))        //如果未访问后继点,dfs访问(会一直递归到最后一个结点)            {                return false;            }        }    }    c[u]=1;          //置为已访问    topo[--t]=u;      //拓扑排序   // cout<<"topt:"<<t<<"="<<u<<endl;    return true;}bool toptsort(){    t=n;    memset(c,0,sizeof(c));     //置为0意味未访问过    for(int u=1;u<=n;u++)    {        if(!c[u])         //寻找未访问过的结点        {            if(!dfs(u))    //若有环            {                return false;            }        }    }    return true;}int main(){    int m,a,b;    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    while(cin>>n>>m&&(n!=0||m!=0))    {        memset(G,0,sizeof(G));        memset(topo,0,sizeof(topo));        for(int i=0;i<m;i++)        {            cin>>a>>b;            G[a][b]=1;        }        toptsort();        for(int i=0;i<n;i++)        {            if(i!=0) cout<<' ';            cout<<topo[i];        }        cout<<endl;    }    return 0;}
注:文章大部分内容引用自刘汝佳《算法竞赛入门经典》(第二版)


原创粉丝点击