ZJU1060 PKU1094
题目大意:
输入n和m,表示字母表的前n个字母,总共有m组小于关系(即A < B这样的关系)。要求能否构成唯一的排序,给出的偏序关系中是否有冲突。注意,如果在第k个关系时就能确定唯一的序列,或产生冲突,那么之后输入的关系一概忽略。
分析:
题目的意思就是要根据这些关系确定是否存在唯一的拓扑关系。
一个很直接的思路就是,每输入一个关系,就对新的关系集合做一次拓扑排序,并判断是否存在环(冲突),是否有多个度为0的节点(排序不唯一),或排序唯一。只要检测到一次冲突或排序成功,之后的关系都不再处理。
这样做不会超时,不过我WA了若干次,最后也不知哪里错了。遂放弃这个思路。POJ的Discuss里面有很人讨论陷阱和其他一些方法,可以去参考一下。例如用BellmanFord或是传递闭包等等……
这里说一下我的解法,不用做拓扑排序。
令b[i][j]表示i是否小于j。即b[i][j]==1表示已知i<j,b[i][j]==0表示不确定。
当得到一个关系x < y时:
若存在b[y][x]==1。则产生冲突。
否则,对于所有的b[i][x]==1,都赋值b[i][y]=1;对于所有的b[y][j]==1,都赋值b[x][j]=1。
这样处理之后,可以得到的b[][]数组既是已知的所有直接和间接的小于关系,判断排序成功也就容易了。
- /*
- ZJU1060
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory.h>
- #define clr(a) memset(a,0,sizeof(a))
- #define N 30
- int n,m;
- int b[N][N];
- int count[N];
- int idx[N];
- int ordered,conflicted;
- int cmp(const void *a,const void *b){
- return count[*(int*)a] - count[*(int*)b];
- }
- int main()
- {
- int i,j,k;
- char s[N],x,y;
- while(scanf("%d%d",&n,&m),n+m){
- //init
- clr(b); clr(count);
- ordered=conflicted=0;
- for(i=0;i<n;i++) idx[i]=i;
- //input
- for(k=1;k<=m;k++){
- scanf("%s",s);
- if(ordered || conflicted) continue;
- x=s[0]-'A'; y=s[2]-'A';
- if(b[y][x]){
- conflicted=k; continue;
- }
- //add relation
- if(b[x][y]) continue;
- b[x][y]=1;
- count[x]++;
- for(i=0;i<n;i++){
- if(b[i][x])
- if(!b[i][y]) b[i][y]=1,count[i]++;
- if(b[y][i])
- if(!b[x][i]) b[x][i]=1,count[x]++;
- }
- //check ordered
- qsort(idx,n,sizeof(int),cmp);
- for(i=0,j=1;i<n && j;i++)
- if(count[idx[i]]!=i) j=0;
- if(j) ordered=k;
- }
- //output
- if(conflicted){
- printf("Inconsistency found after %d relations./n",conflicted);
- }
- else if(ordered){
- printf("Sorted sequence determined after %d relations: ",ordered);
- for(i=n-1;i>=0;i--) printf("%c",idx[i]+'A');
- printf("./n");
- }
- else{
- puts("Sorted sequence cannot be determined.");
- }
- }
- return 0;
- }