题目翻译
N 头奶牛,编号 1∼N,一起参加比赛。奶牛的战斗力两两不同。这些奶牛之间已经进行了 M 轮两两对决。
在对决中,战斗力高的奶牛一定会战胜战斗力低的奶牛。请问,通过上述 M轮对决的结果,可以确定多少头奶牛的具体战斗力排名。
输入格式
第一行包含两个整数 N,M。
接下来 M行,每行包含两个整数 a,b,表示奶牛 a 和奶牛 b之间进行了对决,并且奶牛 a战胜了奶牛 b。
输出格式
输出可以确定具体战斗力排名的奶牛数量。
数据范围
1
≤
N
≤
100
1≤N≤100
1≤N≤100
1
≤
M
≤
4500
1≤M≤4500
1≤M≤4500
数据保证合法。
输入样例:
5 5
4 3
4 2
3 2
1 2
2 5
输出样例:
2
样例解释
2号奶牛输给了 1,3,4号奶牛,战胜了 5号奶牛,可以确定它的战斗力排名为 4。5号奶牛输给了排在第 4 的2号奶牛,所以它的战斗力排名为 5。其它奶牛不确定。
题解:
这道题是传递闭包("有向“)的模板题。
传递闭包问题:在交际网络中,给定若干个元素和若干对二元关系,且关系具有传递性。”通过传递性推导出尽量多的元素之间的关系“的问题。
可以用Floyd算法解决该问题。
我们用邻接矩阵来存储奶牛之间的战斗力的大小关系。
d
[
i
]
[
j
]
=
1
d[i][j] = 1
d[i][j]=1表示i号奶牛的战斗力强于j号奶牛。如果奶牛i的战斗力强于奶牛k,而奶牛k的战斗力强于奶牛j,我们可以推出奶牛i的战斗力强于奶牛j,因此该二元关系具有传递性。我们只需要这样状态转移:
d[i][j] |= d[i][k] & d[k][j];
最后我们只需要枚举每个奶牛(设该奶牛为i号)。对于任意的其他奶牛 j j j,都满足 d [ i ] [ j ] d[i][j] d[i][j]和 d [ j ] [ i ] d[j][i] d[j][i]有一个为1,则i号奶牛的排名确定。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 105;
int d[N][N];
int main(){
int n, m, i, j, k, x, y, ans;
bool flag;
scanf("%d%d", &n, &m);
for(i = 1; i <= m; i++){
scanf("%d%d", &x, &y);
d[x][y] = 1;
}
//传递闭包
for(k = 1; k <= n; k++)
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
d[i][j] |= d[i][k] & d[k][j];
ans = 0;
for(i = 1; i <= n; i++){
flag = 1;
for(j = 1; j <= n; j++){
if(j != i && d[i][j] == 0 && d[j][i] == 0){
flag = 0;
}
}
if(flag)
ans++;
}
printf("%d", ans);
return 0;
}