POJ1094 拓扑排序

来源:互联网 发布:网络暴力数据 编辑:程序博客网 时间:2024/06/05 08:57

题目内容

链接:POJ1094

算法详解

Kahn算法

摘抄维基百科上对于Kahn算法的伪代码描述:

L← Empty list that will contain the sorted elementsS ← Set of all nodes with no incoming edgeswhile S is non-empty do    remove a node n from S    insert n into L    foreach node m with an edge e from nto m do        remove edge e from thegraph        ifm has no other incoming edges then            insert m into Sif graph has edges then    return error (graph has at least onecycle)else     return L (a topologically sortedorder)

其实概要一下,几句话就可以了:

  1. 寻找入度为0的点。
  2. 如果有多个,说明无法排序
  3. 如果没有入度为0的点,且图中有节点,说明有环
  4. 如果有一个入度为0的点,把这个点排到队伍后面,然后把图中这个点去掉
  5. 图中什么都没有的时候结束运算,不然就循环到1。

题解

该题作为拓扑排序实现的经典题,在lrj的《算法竞赛入门经典(第二版)》中P167有原题。书中使用了DFS作为拓扑排序的方法,但是个人觉得利用DFS进行拓扑排序无论从算法效率和编码难度上都存在问题。
于是采用了根据当前无入度点检索进行排序的方法,编码难度瞬间下降。算法详见算法详解。

编码注意点

注意char,int类型转换

#define getid(letter) (letter - 'A')#define getletter(id) (char)(id + 'A')

无法排序的时候依旧要继续执行

在topsort函数中有这么一行:

// 这里不return因为不知道后面存不存在环 if(zeroNum > 1)     flag = 0; // uncertain if(zeroNum == 0)    return -1; // 有环 

原本我的实现如下,在发现有多个入度为0(无法确定排序)的时候退出算法:

// 这里不return因为不知道后面存不存在环 if(zeroNum > 1)     return  0; // uncertain if(zeroNum == 0)    return -1; // 有环 

这个编码获得了OJ上W的结果。原因在于,虽然这时候可以肯定这个序列是无法确定排序的,但是万一后面几个点存在环的时候呢?以下图为例进行说明:

graph LR    A --> B    C --> B    B --> D    D --> E    E --> B

图中A,C为入度为0的点,如果直接返回0的话,会忽略对后面BED环的检测工作,于是原本应该输出Inconsistency found after %d relations. 的结果,却只能输出 Sorted sequence cannot be determined.

所以当发现存在多个入度为0的点的时候,依旧要继续检测后面的节点,检测是否存在环。

源代码

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define maxn 30#define rep(i,n) for(int i = 0;i < n;i++)#define getid(letter) (letter - 'A')#define getletter(id) (char)(id + 'A')// the definition of graphint G[maxn][maxn];// the indegree of nodeint indeg[maxn];// sorted arraychar s[maxn];// N -> node num// M -> edge numint N,M;// ret: 0 -> uncertain -1 -> inconsistency 1 -> okint topsort(){        int in[maxn];    s[N] = '\0';    int flag = 1;        // copy indeg     rep(i,N){        in[i] = indeg[i];    }    rep(i,N){        int zeroNum = 0;        int zeroPos = -1;        // find indegree zero        rep(j,N){            if(in[j] == 0){                zeroPos = j;                zeroNum++;            }        }         // 这里不return因为不知道后面存不存在环         if(zeroNum > 1)     flag = 0; // uncertain         if(zeroNum == 0)    return -1; // 有环                 s[i] = getletter(zeroPos);        // decrease indegree for the remove of zeroPos        in[zeroPos] = -1;        rep(j,N){            if(G[zeroPos][j])                in[j]--;        }    }        return flag;}int main(){    char temp[5];        while(scanf("%d%d",&N,&M)!=EOF){        if(N == 0 && M ==0) break;        memset(G,0,sizeof(G));        memset(indeg,0,sizeof(indeg));                int flag = 0;        rep(i,M){            scanf("%s",temp);            if(flag)    continue;                        // add to map            int from = getid(temp[0]);            int to = getid(temp[2]);            G[from][to] = 1;            indeg[to]++;            // top sort            int ans = topsort();                        if(ans == -1){                flag = 1;                printf("Inconsistency found after %d relations.\n",i+1);            }else if(ans == 1){                flag = 1;                printf("Sorted sequence determined after %d relations: %s.\n",i+1,s);            }        }                if(!flag)            printf("Sorted sequence cannot be determined.\n");                }            return 0;} 
原创粉丝点击