POJ1094(Topological Sort)

1094:Sorting It All Out

时间限制:     

1000ms  

内存限制:     

65536kB 

描述

An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B, C, D implies that A < B, B < C and C < D. in this problem, we will give you a set of relations of the form A < B and ask you to determine whether a sorted order has been specified or not.

输入 

Input consists of multiple problem instances. Each instance starts with a line containing two positive integers n and m. the first value indicated the number of objects to sort, where 2 <= n <= 26. The objects to be sorted will be the first n characters of the uppercase alphabet. The second value m indicates the number of relations of the form A < B which will be given in this problem instance. Next will be m lines, each containing one such relation consisting of three characters: an uppercase letter, the character "<" and a second uppercase letter. No letter will be outside the range of the first n letters of the alphabet. Values of n = m = 0 indicate end of input.

输出

For each problem instance, output consists of one line. This line should be one of the following three:

Sorted sequence determined after xxx relations: yyy...y.
Sorted sequence cannot be determined.
Inconsistency found after xxx relations.

where xxx is the number of relations processed at the time either a sorted sequence is determined or an inconsistency is found, whichever comes first, and yyy...y is the sorted, ascending sequence.

样例输入

4 6

A<B

A<C

B<C

C<D

B<D

A<B

3 2

A<B

B<A

26 1

A<Z

0 0

样例输出

Sorted sequence determined after 4 relations: ABCD.

Inconsistency found after 2 relations.

Sorted sequence cannot be determined.

Help1:拓扑排序:先判断是否有环,再判断是否有序,最后才能判断是否能得出结果。必须遍历完整个图才能知道是否有环。

Help2:在网上看到这样的提示 
“对于前i-1条边已确立完整的拓扑关系但是在第i条边后又出现环的输入,算作无环图,也就是说,对于输入2 2 A<B B<A,应输出Sorted sequence determined after 1 relations: AB,而且题目和范例都没有提到这一点,吐血” 

Help3第一次很快用拓扑排序把代码敲出来,提交,wa,仔细分析后,发现忽略了重复边的情况,插入边(u, v),如果图g已经存在了边(u,v),就不能再增加v的入度。
很快改过来,提交,还是wa,很无奈,上网看看大牛评论,原来是只要当前输入数据能确定唯一,及时后面输入数据有环,也是判定为确定唯一。也就是说,每输入一条边,如果判定有结果,忽略后面输入数据,即使后面输入数据能改变结果。
再改,再提交,还是wa,几度欲放弃之,还是坚持下来了,上google找别人代码来分析,结果发选只要当前输入数据有环,及时当前输入数据不能确定唯一,也是判定为有环

Help4题意就不说了,很明显的拓扑排序。借这道题总结一下拓扑排序吧。拓扑排序的思路很明确但我总觉得有很多的细节值得注意,写的时候总是缺点这少点那的,不断的调试总是浪费很多的时间,以下是我总结的几点:

(1)拓扑排序的结果一般分为三种情况:1、可以判断 2、有环出现了矛盾 3、条件不足,不能判断,思路上一定要分清楚三种情况的条件判断。

(2)初始化栈的时候,将入度为零的顶点入栈,然后弹出栈顶元素e,将e的邻接点的入度减一,若邻接点的入度也为零了,将该邻接点也入栈,如此循环,直到栈空。在这个过程中,栈中元素个数始终为一。若大于一则出现了多个顶点入度为零的情况,这时就无法辨别这几个顶点的先后顺序,这也就是条件不足的情况。若入度为零的顶点的个数为零,也就出现了环的情况,但这一情况必须是在弹出的元素的个数小于顶点总个数,所以在结束的时候需要将计数器与总个数相比较,因为会出现这样的情况:A<B,B<C,C<A,D<E,一开始时将D进栈,然后D出E进,E出时没有元素可进了,若不在最后再进行一次比较的话,那么就认为可以判断了,然而其实是有环的。

再说说这道题吧,这道题不仅需要判断这三种情况,而且还要判断在处理第几个关系时出现前两种情况,对于本道题来说三种情况是有优先级的。前两种情况是平等的谁先出现先输出谁的相应结果,对于第三种情况是在前两种情况下都没有的前提下输出相应结果的。

附带几组测试数据:

6 5
A<D
B<C
A<B
D<E
C<D
Sorted sequence cannot be determined.

6 6
A<D
B<C
E<F
B<A
D<E
A<B
Inconsistency found after 6 relations.

6 6
D<E
B<F
A<D
F<C
A<F
E<B
Sorted sequence determined after 6 relations: ADEBFC.

3 3
A<B
B<C
C<A
Sorted sequence determined after 2 relations: ABC.

4 6
A<B
A<C
B<C
C<D
B<D
A<B
Sorted sequence determined after 4 relations: ABCD.

3 2
A<B
B<A
Inconsistency found after 2 relations.

2 2
A<B
B<A
Sorted sequence determined after 1 relations: AB.

2 0

Sorted sequence cannot be determined.

 

#include"iostream"
#include"queue"
#include"vector"
#include"cstring"//for memset
using namespace std;
int mat[26][26];
int updating[26][26];
//以下两个全局用于topo函数,注意要实时更新
vector<int> sorted(26);
bool has_add[26];
bool topo(int pass[26][26],int num,int times);
int main()
{
 int n,x;
 char temp[4];
 while(cin>>n>>x&&!(n==0&&x==0))
 {
  memset(mat,0,sizeof(mat));//初始状态没有弧和路径
  bool done=false;//初始done值为false
  for(int i=0;i<x;i++)//for循环逐步构造弧并寻找路径
  {
   cin>>temp;
            mat[temp[0]-'A'][temp[2]-'A']=1;
   if(!done)//当已经确定顺序后,后面输入的规则就没有用了
   {
    done=topo(mat,n,i+1);//i+1是判定条件的数目,最后一次是先输出结果再返回true
   }
  }
  if(!done)       
   cout<<"Sorted sequence cannot be determined.\n";        
 }      
}        
bool topo(int pass[26][26],int num,int times)
{
 for(int i=0;i<num;i++)//复制pass给updating
  for(int j=0;j<num;j++)
   updating[i][j]=pass[i][j];  
 //刷新sorted和has_add             
 sorted.clear();         
 memset(has_add,false,sizeof(has_add));       
 int will_add;//用于存储将要入队的节点并作为监视哨
 while(1)
 {
    //以下利用for循环查找入度为0的节点,逐步增长路径长度
 //注意了,for循环外面要用while(1),再利用has_add[i]来控制是否跳出while循环,
    //因为入度为0的节点不一定是总是循环开头的0,而有可能是i++后的其他数
 will_add=-1;//监视哨,当n个节点除了已经入队于sorted_res中的节点后没有一个是入度为0的时候
 for(int i=0;i<num;i++)   
 {   
  if(has_add[i]==true)    
   continue;  
       bool can_add=true;
    for(int j=0;j<num;j++)//寻找入度为0的节点以入队
    {
          can_add=can_add&&(updating[j][i]==0);        
    }                                                                              
    if(can_add)             
    {              
    will_add=i;                 
    break;                        
    }                                                
 }//end outer for     
 if(will_add==-1)//处理监视哨,跳出while(1)循环,当n个节点除了已经入队于sorted_res中的节点后没有一个是入度为0的时候
  break;
  has_add[will_add]=true;       
  sorted.push_back(will_add);           
      //后期处理,删除所有以当前节点为弧头的弧        
      for(int j=0;j<num;j++)                         
    updating[will_add][j]=0;         
 }//end while(1)
 if(sorted.size()<num)
 {
  cout<<"Inconsistency found after "<<times<<" relations.\n";
   return true;                            
 }     
 bool strict=true;
 if(sorted.size()==num)
 {
   for(int i=0;i<sorted.size()-1;i++)
   {
    strict=strict&&(pass[sorted[i]][sorted[i+1]]==1);//此处必须用pass来判定序列是否完全确定为有序
   }
 }
 if(strict==true)           
 {
   cout<<"Sorted sequence determined after "<<times<<" relations: ";
   for(int i=0;i<sorted.size();i++)
    cout<<(char)(sorted[i]+'A');
   cout<<"."<<endl;
   return true;
 }
 else
      return false;
}

原文地址:https://www.cnblogs.com/lzhitian/p/2140069.html