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;
}