题意
公牛比赛, 给出一些等级关系, 如 A B 表示 A 能够战胜 B
求有多少只公牛的排名能够确定
思路
一眼看成拓扑排序, 很久没做过拓扑忘了怎么写, 又因为个人赛不能查阅资料, 就没能继续想下去. 可是题目并没有要求具体的排序顺序. 在这道题中, 所谓战胜关系是可以传递下去的, 比如 A 战胜 B , B 战胜 C, 则 A 能够战胜 C. 典型的floyed求传递闭包
讲道理, 训练前刚就做了紫书P364-365的那个传递闭包(UVa247), 可是看到题目却没有深入想到它的正确解法, 说明思维太僵化, 而且也没有把这个算法理解到位.
突破点 : 通过做出传递闭包建图, 遍历一遍, 若某点的入度 + 出度 == n - 1
则该公牛的排名能够被确定
AC代码
//POJ 挂了 等AC后再来放代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 105;
int g[maxn][maxn];
int in[maxn], out[maxn]; //入度 出度
int n, m;
void floyed()
{
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
g[i][j] = g[i][j]||(g[i][k]&&g[k][j]);
}
int main()
{
int a, b;
scanf("%d%d",&n,&m);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &a, &b);
g[a][b] = 1;
}
floyed();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if( g[i][j] )
{
out[i] += 1;
in[j] += 1;
}
int ans = 0;
for(int i = 1; i <= n; i++)
if( out[i]+in[i] == n-1 )
ans += 1;
printf("%d\n", ans);
return 0;
}