胜负关系
给定一张游戏胜负表,上面有 N 个人以及 M 个胜负关系,每个胜负关系为 A B,表示 A 能胜过 B,且胜负关系具有传递性。即 A 胜过 B,B 胜过 C,则 A 也能胜过 C。求出有多少对选手的胜负无法预先得知
输入第一行给出数据组数,每组数据第一行给出 N 和 M(N , M <=500),接下来 M 行,每行给出 A B,表示 A 可以胜过 B
输出对于每一组数据,判断有多少场比赛的胜负不能预先得知。注意 (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算法的一个应用就是求图内的传递闭包,求出任意两点的传递关系
- 使用bool型数组v来记录,v[i][j]来表示i是否能胜过j
- 进行三重循环后得出所有的选手之间的胜负关系,由于题目中给出ab与ba等价,所以最终记录的数目除以2
- 三重循环的Floyd需要注意就是中间点要放到最外层去循环
void floyd(int n,int **dis)
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=dis[i][k]+dis[k][j];
}
- 复杂度是O(n3)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool v[501][501];
int main()
{
int N;
cin>>N;
while(N--)
{
int n,m;
memset(v,0,sizeof(v));
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
v[a][b]=true;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(v[j][i])
{
for(int k=1;k<=n;k++)
{
if(v[i][k]) //传递
v[j][k]=true;
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
if(!v[i][j]&&!v[j][i])//无胜负关系
ans++;
}
}
ans=ans/2;//每个二元组 只计算一次
cout<<ans<<endl;
}
return 0;
}