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