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)
其实概要一下,几句话就可以了:
- 寻找入度为0的点。
- 如果有多个,说明无法排序
- 如果没有入度为0的点,且图中有节点,说明有环
- 如果有一个入度为0的点,把这个点排到队伍后面,然后把图中这个点去掉
- 图中什么都没有的时候结束运算,不然就循环到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;}
阅读全文
0 0
- Poj1094拓扑排序总结
- 拓扑排序 poj1094
- poj1094 拓扑排序
- poj1094 拓扑排序
- poj1094拓扑排序
- POJ1094(拓扑排序)
- 拓扑排序poj1094
- poj1094 拓扑排序
- poj1094----拓扑排序
- 拓扑排序POJ1094
- poj1094(拓扑排序)
- POJ1094(简单拓扑排序)
- POJ1094 拓扑排序
- poj1094(拓扑排序)
- 拓扑排序(poj1094)
- POJ1094 拓扑排序
- poj1094(拓扑排序应用)
- poj1094 好一个拓扑排序
- MaxCompute 2.0 NewSQL演进之路
- 打造自己的kali linux渗透利器--巡风扫描器安装
- Android系统根目录结构及说明
- 增强for
- 理解卷积
- POJ1094 拓扑排序
- Tensorflow入门笔记
- 初步探索Android的蓝牙实现
- 性能测试之工具对比-ngrinder jmeter loadunner及ngrinder安装使用方法
- POJ3041 匈牙利算法
- JavaScript小技巧:!!的使用
- 我理解的JavaScript闭包
- 复习SQL
- 909422229_JavaWeb Excel模板导出数据