问题描述
假设给我们一个任意的图,它可能是也可能不是DAG(有向无圈图),推广拓扑排序算法,以使得给定有向图G的输入,它的输出是以下两者之一:
(a) 一个拓扑排序,于是确定了G为DAG;
或者
(b) G中的一个圈,于是确定了G不是DAG.
输入
第一行两个数n,m,代表节点数和边数
m行,每行两个数代表一条有向边
输出
YES
一个拓扑序,数字之间用逗号分隔。
或者
NO
一个圈,数字之间用逗号分隔。
JAVA实现
package sort;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Vector;
public class Main {
public static void main(String[] args) {
//用于输出的vector
Vector<Integer> out = new Vector<Integer> ();
Scanner sc = new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
int[][] matrix=new int[n][n];
// outMatrix(matrix);
// System.out.println("-------------------------------");
/* 给矩阵赋值*/
for(int i=0;i<m;i++){
matrix[sc.nextInt()-1][sc.nextInt()-1]=1;
}
// outMatrix(matrix);//
sc.close();
for(int i=0;i<n ;i++){ //依次检查第i列,即为i+1号定点的输入量
if(!out.contains(i+1)){ //i+1号还没有成功输出
boolean goon=true;
int j=0;
while(goon){
if(matrix[j][i]==0){ //i+1号没有来自j+1号的输入
if(j!=n-1) j++;
else{
out.add(i+1);
goon=false;
//清除此顶点的输出边
for(int k=0;k<n;k++){
matrix[i][k]=0;
}
i=-1;
}
}else{ //有输入
goon=false;
}
}
}
}
// System.out.println(out.size());
/* 遍历输出结果*/
int comma=1;
if(out.size()==n){//是DAG 输出拓扑排序
System.out.println("YES");
Iterator<Integer> iter = out.iterator();
while(iter.hasNext()){
int value = (int)iter.next();
if(comma!=n){
System.out.print(value+",");
comma+=1;
}else System.out.print(value);
}
}else{//不是DAG 输出圈
/* 已经扔出了部分DAG,这些肯定不在某个圈里。
再扔出所有“死路”有输入没有输出的点。
剩下的点一定属于某个圈中。*/
System.out.println("NO");
Vector<Integer> Noout = new Vector<Integer> ();
for(int i=0;i<n-1;i++){
if(!out.contains(i+1)){ //i+1号还没被扔进垃圾桶
boolean goon=true;
int j=0;
while(goon){
if(matrix[i][j]==0){ //i+1号没有给j+1号输出
if(j!=n-1) j++;
else{
out.add(i+1); //此时out不再存储拓扑排序序列,而是“垃圾桶”
goon=false;
//清除此顶点的输入边
for(int k=0;k<n;k++){
matrix[k][i]=0;
}
i=-1;
}
}else{ //有输入
goon=false;
}
}
}
}
/* 输出一个圈*/
//确保第一个顶点是在某个环里面
int first=0;
while(out.contains(first+1)){
first+=1;
}
Noout.add(first+1);
boolean loop=true;
while(loop){
for(int i=0;i<n;i++){
if(matrix[first][i]==1){//找到下一个顶点i+1号
if( Noout.contains(i+1)){//已经有i+1号了,说明找到一个环
first=i;//环的开头顶点
loop=false;
break;
}
Noout.add(i+1);
first=i;
i=-1;
}
}
}
//最终输出 从first开始
boolean begin=false;
Iterator<Integer> it = Noout.iterator();
// System.out.println("Here!!");
// System.out.println(Noout.size());
while(it.hasNext()){
int value = (int)it.next();
if(value==first+1){
begin=true;
}
if(begin){
System.out.print(value+",");
}
}
System.out.print(first+1);
}
}
//输出矩阵
static void outMatrix (int [][] matrix){
for(int i=0;i<matrix.length;i++){
for(int j=0;j<matrix[i].length;j++){
System.out.print(matrix[i][j]+" ");
}
System.out.println();
}
}
}
结果展示
输入:
5 5
1 2
1 3
2 5
3 4
4 5
输出:
YES
1,2,3,4,5
输入:
5 7
1 2
1 3
2 1
2 5
3 4
4 2
4 5
输出:
NO
1,2,1