原题链接:http://poj.org/problem?id=1094
同ZOJ 1060:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1060
Sorting It All Out
Time Limit: 1000MS |
|
Memory Limit: 10000K |
Total Submissions: 21983 |
|
Accepted: 7574 |
Description
Anascending sorted sequence of distinct values is one in which some form of aless-than operator is used to order the elements from smallest to largest. Forexample, 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
Inputconsists of multiple problem instances. Each instance starts with a linecontaining two positive integers n and m. the first value indicated the numberof objects to sort, where 2 <= n <= 26. The objects to be sorted will bethe first n characters of the uppercase alphabet. The second value m indicatesthe number of relations of the form A < B which will be given in thisproblem instance. Next will be m lines, each containing one such relationconsisting of three characters: an uppercase letter, the character"<" and a second uppercase letter. No letter will be outside therange of the first n letters of the alphabet. Values of n = m = 0 indicate endof input.
Output
For eachproblem instance, output consists of one line. This line should be one of thefollowing 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 sortedsequence is determined or an inconsistency is found, whichever comes first, andyyy...y is the sorted, ascending sequence.
SampleInput
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
SampleOutput
Sorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations.
Sorted sequence cannot be determined.
Source
EastCentral North America 2001
算法:图论之拓扑排序。
题意 : 按照升序序列匹配字符串。
关于输入:
题目包含一系列的测试样例。
首先在第一行给你两个数字n(n>=2&& n<=26)和m。
n代表一共要匹配n个不同的字符;
m以"A<B"的形式给你m个字符间这样的关系;
那么接下来的m行当然是以"A<B"的形式输入这些关系了。
如果输入0 0,则结束程序。
输出:
题目有三种输出形式:
第一:字符的关系产生了矛盾。(PS:产生了环)
对于两个字符 'A' 和 'B',如果有一行输入(或者根据前面的输入推出)的 是"A<B",而在第q(1<q<=m)行输入(或者根据输入推出)"A>B".那么就 产生了矛盾。
输出:Inconsistency found after qrelations.
比如说题目中的样例2就是这种情况。
3 2
A<B
B<A
第二行和第一行产生矛盾。(出现了环)
注意:对于样例2,其实也是输入无法匹配的情况,但是却没有输出他们 无法匹配,所以在写程序时要注意这两种情况的输出顺序先判断他们是否矛盾,
如果矛盾就直接输出矛盾,进入下一轮样例。
第二种情况:字符无法匹配成功。
输出:Sorted sequence cannot be determined.
例如样例3:26 1
A<Z
要匹配26个字符,而只输入了两个字符。
(PS:输入n,则定是要匹配前N个大写字母)。
第三种情况:字符匹配成功:
输出:Sorted sequence determined after n relations:
此处按升序输出字符。
例如样例1的输出:
Sorted sequencedetermined after 4 relations: ABCD.
拓扑排序:
1 在有向图中选择一个没有前驱(即入度为0)的顶点并输出之。
2 在有向图中删除刚刚输出的顶点及所有以该顶点为尾的弧。
3 图中若不再有入度为0的顶点,则结束;否则转①。
PS:偏序是指集合中仅有部分元素可比较大小(或先后);
全序是指集合中所有元素均可比较大小(或先后)。
拓扑排序就是由偏序关系得到全序关系。
算法思想来自:课件16有向无环图及其应用。
参考牛人代码:http://blog.163.com/wojiaojason@126/blog/static/1240982842010214105332122/
code一:
//Accepted 228K 0MS C++ 1791B #include<stdio.h> #include<string.h> int map[27][27]; int in_degree[27],cnt[27],sort[27]; int n,m; char str[4]; int topo() { int i,j; int num,flag,now=0,s; flag=now=0; memset(sort,0,sizeof(sort)); for(i=1;i<=n;i++) cnt[i]=in_degree[i]; for(i=1;i<=n;i++) { num=0; for(j=1;j<=n;j++) { if(cnt[j]==0) { num++; s=j; }//用cnt记录,免得修改了sum数组的值; } if(num==0) return 0;//如果没有入度为0的点,则表示有环,矛盾 if(num>1) flag=1;//只有入度为0的点只有一个,才能排序,易错点:直接return -1; sort[now++]=s;//入队 cnt[s]=-1;//标记已入队 for(j=1;j<=n;j++) if(map[s][j]) cnt[j]--;//删边 } if(flag) return -1;// return 1; } int main() { int i,j; int ans,sign; int u,v; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0 || m==0) break; sign=0;//标记结果 memset(map,0,sizeof(map)); memset(in_degree,0,sizeof(in_degree)); for(i=1;i<=m;i++) { scanf("%s",str); if(sign) continue; u=str[0]-'A'+1;v=str[2]-'A'+1; map[u][v]=1;//字符数字化记录 in_degree[v]++;//记录入度 ans=topo(); if(ans==0)//矛盾 { printf("Inconsistency found after %d relations.\n",i); sign=1; } if(ans==1)//成功排序并且输出 { printf("Sorted sequence determined after %d relations: ",i); for(j=0;j<n;j++) printf("%c",sort[j]+'A'-1); printf(".\n"); sign=1; } } if(!sign)//不能排序 printf("Sorted sequence cannot be determined.\n"); } return 0; }
易错点分析:(By Kuangbin)
为何入度为0的点的个数num>1不直接返回-1,而是要用flag标记。
反例:对于有环图:A<B、B<C、C<A矛盾。
比如这种图,应该返回0呢
直接返回-1就不对了。虽然现在不矛盾,但是到后面可能就矛盾了
看下面的输入,如果没有flag则
5 5
A<B
B<C
C<A
Inconsistency found after 4 relations.
但是正确的结果应该是:
5 5
A<B
B<C
C<A
Inconsistency found after 3 relations.
如果实在无法理解图论问题,则可以看我在网上看的另外一个人的代码:
/来源:/http://blog.sina.com.cn/s/blog_5ced353d0100b4xs.html
//AC 184kb 0ms
Ø 思路:按照输入,对给的每个字符都进行一番比较,比如说有n 个字符,那么就要比较出num=n(n-1)/2次不同的"A<B"形式。
Ø 如果匹配成功了,那么一定会有num个不同的"A<B"的形式的字符比较。
Ø 如何比较:因为n<=26,所以设立一个比较数组cmpMap[26][26]用其来存储字母间的大小关系,cmpMap[i][j]=0表示第i个字母和第j个字母大小未定;
1表示第i个字母小于第j个字母;
-1表示第i个字母大于第j个字母。
在题目输入m个字符间的关系前全部赋值为0,表示不知道字符间的关系。
关于输入m个(A<B形式)字符间的关系:
Ø 用一个一位数组s[4]来存储。
Ø 假设当前输入为s[3],则若s[0]==s[2],出现矛盾,
Ø 若s[0]!=s[2]且cmpMap[s[0]-'A'][s[2]-'A']==-1,也出现矛盾
Ø 若s[0]!=s[2]且cmpMap[s[0]-'A'][s[2]-'A']==1,s[0]与s[2]已经有序,故不做操作
Ø 若s[0]!=s[2]且cmpMap[s[0]-'A'][s[2]-'A']==0,扫描所有小于s[0]的字母和s[0],下标为i,所有大于s[2]的字母和s[2],下标为j,则若cmpMap[i][j]==1,已排好序,不做操作,若cmpMap[i][j]==0,置cmpMap[i][j]=1,cmpMap[j][i]=-1,num++。
Ø num为cmpMap中值为1的元素的个数。可知当num==n*(n-1)/2时,全部字母都排好序。(这一点前面已经提及)
Ø 要点:s中存3个字符,故应为char s[4],写成char s[3];出现segmentation fault错误,注意:'\0'。
#include <stdio.h> int cmpMap[26][26],biggerNum[26]; int main() { //freopen("in.txt","r",stdin); intn,m,i,j,num,q,inconsistency,succeed; chars[4]; while(scanf("%d%d",&n,&m)) { if(n==0&& m==0) break; num=0; inconsistency=0; succeed=0; for(i=0;i<n;i++) for(j=0;j<n;j++) cmpMap[i][j]=0; for(q=1;q<=m;q++) { scanf("%s",s); if(s[0]==s[2]|| cmpMap[s[0]-'A'][s[2]-'A']==-1) // s[0]与s[2]出现矛盾 { inconsistency=1; break; } if(cmpMap[s[0]-'A'][s[2]-'A']==1) //s[0]与s[2]已有序 continue; for(i=0;i<n;i++) //s[0]与s[2]无序 if(cmpMap[s[0]-'A'][i]==-1|| (s[0]-'A')==i) //扫描所有小于s[0]的字母和s[0] { for(j=0;j<n;j++) if((cmpMap[s[2]-'A'][j]==1|| (s[2]-'A')==j) && cmpMap[i][j]==0)//扫描所有大于s[2]的字母和s[2] { //cmpMap[i][j]==0表示第i个字母和第j个字母无序 cmpMap[i][j]=1; cmpMap[j][i]=-1; num++; } } if(num==n*(n-1)/2) //num==n*(n-1)/2代表所有字母已排序 { succeed=1; break; } } if(inconsistency) printf("Inconsistencyfound after %d relations.\n",q); elseif(succeed) { printf("Sortedsequence determined after %d relations: ",q); //输出排好序的字母序列 for(i=0;i<n;i++) biggerNum[i]=0; for(i=0;i<n;i++) for(j=0;j<n;j++) if(cmpMap[i][j]==1) biggerNum[i]++;//找出有多少个字母比i大 for(i=n-1;i>=0;i--) { for(j=0;j<n;j++) if(biggerNum[j]==i) { printf("%c",'A'+j); break; } } printf(".\n"); } else printf("Sortedsequence cannot be determined.\n"); if(q<m) for(q++;q<=m;q++) scanf("%s",s); } return0; }