勝負關係
給定一張遊戲勝負表,上面有 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;
}