zoukankan      html  css  js  c++  java
  • 拓扑排序 POJ 1094 Sorting It All Out

    题意:给定N个字和M行他们之间的关系,要求输出他们的拓扑排序。此题采用边输入边检测的方式,如果发现环,就结束并输出当前行号;如果读取到当前行时,可以确定拓扑序列就输出,不管后面的输入(可能包含环路);如果到最后还是不能确定拓扑序列,就输出指定的字符串。

    拓扑排序:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若 ∈E(G),则u在线性序列中出现在v之前。

    分析:首先,拓扑排序的算法还是挺直观的。简单的拓扑排序算法:先找到任意一个没有入边的顶点,然后是显示该顶点,并将它和它的边一起从图中删除。然后,对图的其余部分应用同样的方法处理。如果找不到没有入边的顶点,说明存在回路。这里的实现过程由于要边输入边检测,所以要注意先一次性读取完输入。还要注意图不是强连通的,以及消去一个顶点后的图不是强连通图的这种情况。做的时候感觉要考虑很多情况,但做完了反而想不起那么多来。呵呵,看代码吧!

    import java.util.Scanner;
    
    public class Main {
    	static int n,m;
    	static int[][] a; //邻接矩阵
    	static int [] degree; //每个节点的入度
    	static boolean[] vis; //记录是否被访问
    	/**
    	 * 拓扑排序,返回排序的序列,返回1说明存在环路。
    	 * @return
    	 */
    	public static String topo(){
    		String s="";
    		for(int i=0;i<n && isIsolatedNode(i);i++){
    			int temp=findInDegreeZero();
    			if(temp!=-1){
    				//消去顶点后的图还是强连通就满足要求
    				if(countZeroDegree()==1)
    					s+=((char)(temp+65));
    				vis[temp]=true;
    				for(int j=0;j<n;j++)
    					if(a[temp][j]==1)
    						degree[j]--;
    			}else{
    				s="1";
    				break;
    			}
    		}
    		return s;
    	}
    	/**
    	 * 读取入度
    	 */
    	public static void readInDegree(){
    		for(int i=0;i<n;i++)
    			for(int j=0;j<n;j++)
    				if(a[i][j]!=0 )
    					degree[j]++;
    	}
    	/**
    	 * 由于采用邻接矩阵,所以要判断节点是否在要排序的N个节点中。利于查找入度为0的节点。
    	 * @param num
    	 * @return
    	 */
    	public static boolean isIsolatedNode(int num){
    		int sum=0;
    		for(int i=0;i<n;i++)
    			sum+=(a[num][i]+a[i][num]);
    		if(sum==0)
    			return false;
    		else
    			return true;
    	} 
    	/**
    	 * 计算入度为零的节点个数,超过一个则说明该图不是强连通图。
    	 * 由于要优先判断是否存在环路,所以不能如果不是强连通图也要等判断是否存在环路。
    	 * @return
    	 */
    	public static int countZeroDegree(){
    		int sum=0;
    		for(int i=0;i<n;i++)
    			if(degree[i]==0 && isIsolatedNode(i) && vis[i]==false){
    				sum++;
    			}
    		return sum;
    	}
    	/**
    	 * 找到入度为0的节点,不存在就返回-1(存在环路)
    	 * @return
    	 */
    	public static int findInDegreeZero(){
    		for(int i=0;i<n ;i++)
    			if(degree[i]==0 && vis[i]==false && isIsolatedNode(i)){
    				return i;
    			}
    		return -1;   
    	}
    	
    	public static void main(String[] args) {
    		Scanner sc=new Scanner(System.in);
    		while(true){
    			n=sc.nextInt();
    			m=sc.nextInt();
    			if(n+m==0)
    				break;
    			a=new int[n][n];
    			String result="";
    			String[] str=new String[m+1];
    		    for(int i=1; i<=m; i++)
    		        str[i]=sc.next();
    		    int i;
    		    for(i=1; i<=m; i++){
    		    	vis=new boolean[n];
    		    	degree=new int[n];
    		        a[str[i].charAt(0)-65][str[i].charAt(2)-65]=1;
    		        readInDegree();
    		        int beginZeroDegree=countZeroDegree();
    		        result=topo();
    		        //如果结果字符串长度和N相同,并且图是强连通的就输出序列
    		        if(result.length()==n && beginZeroDegree==1){
    		        	System.out.println("Sorted sequence determined after "+i+" relations: "+result+".");
    		        	break;
    		        //如果存在环路则输出
    		        }else if(result.equals("1")){
    		        	System.out.println("Inconsistency found after "+i+" relations.");
    		        	break;
    		        }
    		    }
    		    //不存在环路,到最后还是不能确定序列
    		    if((i-1)==m && result.length()!=n)
    		    	System.out.println("Sorted sequence cannot be determined.");
    		}
    	}
    }
    



    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    软件测试人员的年终绩效考核怎么应对
    收藏
    顶踩组件 前后两版
    订阅组件
    hdu 1963 Investment 完全背包
    hdu 4939 Stupid Tower Defense 动态规划
    hdu 4405 Aeroplane chess 动态规划
    cf 414B Mashmokh and ACM 动态规划
    BUPT 202 Chocolate Machine 动态规划
    hdu 3853 LOOPS 动态规划
  • 原文地址:https://www.cnblogs.com/AndyDai/p/4734110.html
Copyright © 2011-2022 走看看