1.首先,回忆之前学的,acwing 1125牛的旅行
可以发现floyd的核心数组 d[ i ][ j ] 本来表示的是 i 和 j 点的距离
但是可以直观明了地表示两个点之间联不联通
如果d[i][j]>inf/2,是很明显两个联通块是不连通的
2.那么此处的隐藏边,是点与点之间的关系,比如A<B 的 "<" 这层的关系 。
d[i][j]数组可以很明了得表达,任意两点之间的关系
所以floyd的d[][]数组真的炒鸡好用。
在本题中,d[][]数组开成 bool 型,可以更好表达 ,两个点之间是否存在关系。
所以,floyd 的 d[ i ][ j ] 数组真的太好用了~
-------------------------------------------------------------------------------------------------------------------------
现在来到什么是传递闭包?
简单来说就是关系的传递
Q1: 怎么判断一堆元素的关系没有传递性?
Ans1:找矛盾。
1. 元素自己和自己本身不可能产生某种关系 d[i][i]==true 就意味着矛盾了
2. 枚举每一对(两两一对)元素 i,j 之间的关系,如果存在 ! d[i][j] && !d[j][i]
就意味着某一对元素之间一点关系都没有
这样就意味着 这一堆元素不可能形成一整段的传递关系
343. 排序
给定 nn 个变量和 mm 个不等式。其中 nn 小于等于 2626,变量分别用前 nn 的大写英文字母表示。
不等式之间具有传递性,即若 A>BA>B 且 B>CB>C,则 A>CA>C。
请从前往后遍历每对关系,每次遍历时判断:
- 如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
- 如果发生矛盾,则结束循环,输出有矛盾;
- 如果循环结束时没有发生上述两种情况,则输出无定解。
输入格式
输入包含多组测试数据。
每组测试数据,第一行包含两个整数 nn 和 mm。
接下来 mm 行,每行包含一个不等式,不等式全部为小于关系。
当输入一行 0 0
时,表示输入终止。
输出格式
每组数据输出一个占一行的结果。
结果可能为下列三种之一:
- 如果可以确定两两之间的关系,则输出
"Sorted sequence determined after t relations: yyy...y."
,其中't'
指迭代次数,'yyy...y'
是指升序排列的所有变量。 - 如果有矛盾,则输出:
"Inconsistency found after t relations."
,其中't'
指迭代次数。 - 如果没有矛盾,且不能确定两两之间的关系,则输出
"Sorted sequence cannot be determined."
。
数据范围
2≤n≤262≤n≤26,变量只可能为大写字母 A∼ZA∼Z。
输入样例1:
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
输出样例1:
Sorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations.
Sorted sequence cannot be determined.
输入样例2:
6 6
A<F
B<D
C<E
F<D
D<E
E<F
0 0
输出样例2:
Inconsistency found after 6 relations.
输入样例3:
5 5
A<B
B<C
C<D
D<E
E<A
0 0
输出样例3:
Sorted sequence determined after 4 relations: ABCDE.
//传递闭包普通版 O(m*n^3)
#include <bits/stdc++.h>
using namespace std;
const int N=26; //只有26个变量,所以开到26
int n,m;
/*
注意都是布尔型,所以加减乘除也对应换成了
位运算符
*/
bool g[N][N]; //用g来表示边
bool d[N][N]; //用d来表示传递闭包
bool st[N]; //表示当前变量有没有被输出
void floyd()
{
memcpy(d,g,sizeof d); //d是传递闭包
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
d[i][j]|=d[i][k]&&d[k][j]; //与&&只要有0就会出0
}
}
int check()
{
for(int i=0;i<n;i++)
{
if(d[i][i]) //如果存在自己小于自己就矛盾了
{
return 2; //返回矛盾类型2
}
}
for(int i=0;i<n;i++) //两两握手的关系
for(int j=0;j<i;j++)
{
if(!d[i][j]&&!d[j][i]) //如果i,j之间一点关系都没有
return 0; //返回矛盾类型0
}
return 1; //没有矛盾,可传递
}
char get_min()
{
for(int i=0;i<n;i++) //我们要找到一个i使得它是还未被输出中的最小的
{
//也就是说我们要找的i不能有j还比它小
if(!st[i])
{
bool flag=true;
for(int j=0;j<n;j++)
{
if(!st[j]&&d[j][i]) //如果j没被输出过,并且 j表示的值<i表示的值
{
flag=false;
break;
}
}
if(flag)
{
st[i]=true; //输出了,置为true
return 'A'+i;
}
}
}
}
int main()
{
while(cin>>n>>m,n||m)
{
memset(g,0,sizeof g); //清空所有边
int type=0; //记录最终答案的类型,0表示不确定,1表示唯一确定
int t; //表示每一个结果对应的轮
for(int i=1;i<=m;i++) //迭代m次
{
char str[5];
cin>>str;
int a=str[0]-'A',b=str[2]-'A';
if(!type) //如果最终的结果不确定
{
g[a][b]=1; //建边,直到结果能确定就不用建了
floyd(); //进行floyd
type=check(); //检查结果是否能够确定
if(type) t=i; //如果已经确定了,记录下迭代次数
}
}
if(!type)
{
puts("Sorted sequence cannot be determined.");
}
else if(type==2)
{
printf("Inconsistency found after %d relations.\n",t);
}
else
{
memset(st,0,sizeof st);
//如果可以确定两两之间的关系
printf("Sorted sequence determined after %d relations: ",t);
for(int i=0;i<n;i++)
printf("%c",get_min()); //从小到大输出
printf(".\n");
}
}
return 0;
}