题目链接:http://poj.org/problem?id=1094
传递闭包:
给定若干元素和若干对二元关系,且关系具有传递性,通过传递性推导出尽量多的元素之间的关系的问题叫做传递闭包。
用d[i,j]=1表示i和j有关系,d[i,j]=0表示i和j没有关系。且d[i][i]始终为1。使用Floyd可以解决闭包问题。
$ d[i,j] |= d[i,k] & d[k,j] $
这道题从头枚举条件。每次枚举便做一次传递闭包,看:
如果两个点之间d[i,j]=d[j,i]=1,那么是不可能的。
如果两个点之间d[i,j]=d[j,i]=0,说明还没有确定完关系。
如果任意i,j,只有d[i,j]=1或d[j,i]=1,那么说明是满足条件的。
对于满足条件的,如果e[i,j]等于1,那么说明i<j,让ans[i]++,即它的优先级高,最后按ans排序,数值越大说明优先级越高。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int N=30; 7 char s[6]; 8 int n,m; 9 int d[N][N],e[N][N]; 10 int floyd(){ 11 memcpy(e,d,sizeof(e)); 12 for(int k=0;k<n;k++) 13 for(int i=0;i<n;i++) 14 for(int j=0;j<n;j++){ 15 e[i][j]|=e[i][k]&e[k][j]; 16 if(e[i][j]==e[j][i]&&e[i][j]&&i!=j) return -1; 17 } 18 for(int i=0;i<n;i++) 19 for(int j=0;j<n;j++) 20 if(e[i][j]==e[j][i]&&!e[i][j]&&i!=j) return 0; 21 return 1; 22 } 23 int main(){ 24 while(~scanf("%d%d",&n,&m)&&n){ 25 memset(d,0,sizeof(d)); 26 bool flag=1; 27 for(int i=1;i<=m;i++){ 28 scanf("%s",s); 29 d[s[0]-'A'][s[2]-'A']=1; 30 if(flag){ 31 int now=floyd(); 32 if(now==-1){ 33 printf("Inconsistency found after %d relations. ",i); 34 flag=0; 35 } 36 else if(now==1){ 37 printf("Sorted sequence determined after %d relations: ", i); 38 pair<int,char> ans[N]; 39 for(int j=0;j<n;j++){ 40 ans[j].first=0; 41 ans[j].second='A'+j; 42 } 43 for(int j=0;j<n;j++) 44 for(int k=0;k<n;k++) if(e[j][k]) ans[j].first++; 45 sort(ans,ans+n); 46 for(int j=n-1;j>=0;j--) printf("%c",ans[j].second); 47 printf(". "); 48 flag=0; 49 } 50 } 51 } 52 if(flag) printf("Sorted sequence cannot be determined. "); 53 } 54 return 0; 55 }
如果这道题中输入不仅有A<B的样式,还有B>A的样式,只需要在输入时做一下操作,使B>A转化成A<B即可。
当然这道题也可以用二分来做。