题意:
有一张游戏胜负表,上面有 N 个人以及 M 个胜负关系,每个胜负关系为 A B,表示 A 能胜过 B,且胜负关系具有传递性。即 A 胜过 B,B 胜过 C,则 A 也能胜过 C。求有多少对选手的胜负无法预先得知。
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
思路:
把每个人看作是一个点,把胜负关系抽象成单向边,题意可看作有向无权图。那么任意两个人的胜负关系是否明确即任意两点之间是否能联通,可利用Floyd能求任意两点之间最短距离的思想。
总结:
在进行dis[i][j] = max(dis[i][j], dis[i][k] & dis[k][j]),对于某一i,k,若dis[i][k]为零,则dis[i][j]不可能改变,所以在循环j之前先判断dis[i][k]可减少无用的操作。
代码:
#include<iostream>
using namespace std;
int dis[505][505];
int max(int a, int b)
{
if (a > b)
return a;
return b;
}
void floyd(int n)
{
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (dis[i][k] == 0)
break;
dis[i][j] = max(dis[i][j], dis[i][k] & dis[k][j]);
}
}
}
}
int main()
{
int z;
cin >> z;
while (z--)
{
int N, M;
cin >> N;
cin >> M;
for (int i = 1; i <= N; i++)
{
for (int j = i + 1; j <= N; j++)
{
dis[i][j] = 0;
dis[j][i] = 0;
}
}
while (M--)
{
int a, b;
cin >> a;
cin >> b;
dis[a][b] = 1;
}
floyd(N);
int num = 0;
for (int i = 1; i <= N; i++)
{
for (int j = i + 1; j <= N; j++)
{
if (dis[i][j] == 0 && dis[j][i] == 0)
num++;
}
}
cout << num << endl;
}
}