题目描述
众所周知,TT 有一只魔法猫。
这一天,TT 正在专心致志地玩《猫和老鼠》游戏,然而比赛还没开始,聪明的魔法猫便告诉了 TT 比赛的最终结果。TT 非常诧异,不仅诧异于他的小猫咪居然会说话,更诧异于这可爱的小不点为何有如此魔力?
魔法猫告诉 TT,它其实拥有一张游戏胜负表,上面有 N 个人以及 M 个胜负关系,每个胜负关系为 A B,表示 A 能胜过 B,且胜负关系具有传递性。即 A 胜过 B,B 胜过 C,则 A 也能胜过 C。
TT 不相信他的小猫咪什么比赛都能预测,因此他想知道有多少对选手的胜负无法预先得知,你能帮帮他吗?
Input
第一行给出数据组数。
每组数据第一行给出 N 和 M(N , M <= 500)。
接下来 M 行,每行给出 A B,表示 A 可以胜过 B。
Output
对于每一组数据,判断有多少场比赛的胜负不能预先得知。注意 (a, b) 与 (b, a) 等价,即每一个二元组只被计算一次。
Sample Input
3
3 3
1 2
1 3
2 3
3 2
1 2
2 3
4 2
1 2
3 4
Sample Output
0
0
4
思路
将选手想象成图中的点,将a战胜b转化为ab两点之间边长为1的有向边,即可应用Floyd算法进行求解。主要是将任意两点之间有向边的更新改为dis[i][j]=max(dis[i][j],dis[i][k]&dis[k][j]),这样当算法结束后,便考虑了所有点作为中间点对胜负关系的传递,即得到了所有胜负关系,若dis[i][j]与dis[j][i]均为零,则表示胜负不明,否则,胜负关系已明确。
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 505;
int n, m, a1, b1, ans, temp;
int dis[N][N];
void Floyd()
{
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
if (dis[i][k] != 0)
{
for (int j = 1; j <= n; j++)
dis[i][j] = max(dis[i][j], dis[i][k] & dis[k][j]);
}
}
int main()
{
scanf_s("%d", &temp);
for (int i = 0; i < temp; i++)
{
memset(dis, 0, sizeof(dis));
scanf_s("%d%d", &n, &m);
ans = 0;
for (int j = 0; j < m; j++)
{
scanf_s("%d%d", &a1, &b1);
dis[a1][b1] = 1;
}
Floyd();
for (int k = 1; k <= n; k++)
for (int l = 1; l <= n; l++)
if (dis[k][l] == 0 && dis[l][k] == 0&&k!=l)
ans++;
ans /= 2;
printf("%d\n", ans);
}
return 0;
}