题目
题解
Floyd解决 传递闭包
若有A<B,那么连边(A,B,1),即d[A][B]=1。
如果有A<B,且B<C,对应有d[A][B]=1,d[B][C]=1,在Floyd算法中,会使 d[A][C] |= d[A][B] & d[B][C] ,所以d[A][C]=1。这就是传递闭包。
实现时,可以边输入边判断。具体输出方案时,可以发现这张传递闭包的图是一个入度为0,1,…,n-1的图,分别对应最大,次大,…,最小。据此,可以免去一次拓扑排序的代码,只需要短小精悍的几个for即可求出方案。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=30;
int n,m;
int d[maxn][maxn];
int check()//判断合法性:-1-不确定 1-已经知道顺序了 0-矛盾
{
int re=1;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(d[i][j] && d[j][i]) return 0;
else if(!d[i][j] && !d[j][i]) re=-1;
// else if(!d[i][j] && !d[j][i]) return -1; debug
return re;
}
int ru[maxn];
char ch[10];
int main()
{
while(scanf("%d%d",&n,&m),n!=0)
{
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++) d[i][i]=1;
bool flag=false;
for(int mi=1;mi<=m;mi++)
{
scanf("%s",ch);
if(flag) continue;
int x=ch[0]-'A'+1,y=ch[2]-'A'+1;
d[x][y]=1;//x<y
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) d[i][j]|=d[i][x]&d[y][j];//仅更新与(x,y)有关的
int c=check();
if(c==0){printf("Inconsistency found after %d relations.\n",mi);flag=true;continue;}
if(c==1)
{
printf("Sorted sequence determined after %d relations: ",mi);
memset(ru,0,sizeof(ru));
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(d[i][j]) ru[i]++;//统计入度
else ru[j]++;//debug 注意i和j,因为统计的是小于关系
for(int i=n-1;i>=0;i--)
for(int j=1;j<=n;j++)
if(ru[j]==i){putchar('A'-1+j);break;}
puts(".");
flag=true;continue;
}
}
if(!flag){puts("Sorted sequence cannot be determined.");continue;}
}
}