经典拓扑排序
3 2 0 1 1 2 2 2 0 1 1 0 0 0
YES NO
题意:给你一组数据,n表示有多少个人,m表示这n人中间有多少种关系,然后就是n个人中m个关系,a b,a表示师傅,b表示徒弟,而题目要求是判断给你这组数据中是否存在即是某个人的师傅,又是其徒弟的关系(也就是 a b,b a,那么a就即是b的徒弟又是师傅)
结题思路:这是一个典型的拓扑排序的例题,很适合学习拓扑排序。可以将每个人看作一个结点,而每个人的师傅的个数则表示这个结点对应的入度。然后通过对每个结点进行遍历,依次找出入度为0的结点,将其拿出,并将其对应指向的结点的入度减1,也就是相当于如果没有这个人后,还有人可以只做师傅,依次循环,直到将所有结点都遍历完,都没有出现找不到这样的人(只可以做师傅的人)则表示没有出现不符合条件的关系,否则有(即图中有回路)
import java.util.Scanner;
public class P3342 {
static int n,m;
static int degree[],visit[];//degree记录每个结点的入度(也就是师傅的个数),visit标记已经访问的结点
static int arc[][];//记录结点之间的指向(谁是谁的师傅,前者是师傅,后者是徒弟)
static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
while(sc.hasNext()){
n=sc.nextInt();
m=sc.nextInt();
if(n==0){
break;
}
init();//初始化
// for(int i=0;i<n;i++){
// System.out.println(i+" degree:"+degree[i]);
// }
if(topoSort()){
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
private static boolean topoSort() {//拓扑排序
int s=0;
while(s<n){
int i=0;
for(;i<n;i++){//找入度为零且没有访问过的结点
if(degree[i]==0&&visit[i]==0){
break;
}
}
if(i==n){//没找到这样的结点,则表示图中有回路,也就是即是师傅又是徒弟的人
return false;
}
s++;
visit[i]=1;//若找到这样的结点,这标记为访问过
for(int j=0;j<n;j++){
if(arc[i][j]==1){//然后除去这个点,也就是对应指向的结点入度减1,继续循环遍历其他所有结点
degree[j]--;
// System.out.println(i+"--->"+j+":"+degree[j]);
}
}
}
return true;
}
private static void init() {
degree=new int[n];
visit=new int[n];
arc=new int[n][n];
for(int i=0;i<m;i++){
int a=sc.nextInt();
int b=sc.nextInt();
if(arc[a][b]==0){//这里注意,一定要防止重边的出现(就是防止给的数据会重复)
arc[a][b]=1;
degree[b]++;
}
}
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu3342(Legal or Not)----- 学习拓扑排序的好例题
原文地址:http://blog.csdn.net/u011479875/article/details/47369949