Floyd求传递闭包:预知胜负。c++

胜负关系

给定一张游戏胜负表,上面有 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;
 } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章