最近刷的图论题,样式变化太多,很多都很难想到,比如说这个题,又学到了一种方法:传递闭包
用大白话来说,就是关系的传递。
看一下题目
N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors.
The contest is conducted in several head-to-head rounds, each between two cows. If cow A has a greater skill level than cow B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B), then cow A will always beat cow B.
Farmer John is trying to rank the cows by skill level. Given a list the results of M (1 ≤ M ≤ 4,500) two-cow rounds, determine the number of cows whose ranks can be precisely determined from the results. It is guaranteed that the results of the rounds will not be contradictory.
Input
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Each line contains two space-separated integers that describe the competitors and results (the first integer, A, is the winner) of a single round of competition: A and B
Output
* Line 1: A single integer representing the number of cows whose ranks can be determined
Sample Input
5 5
4 3
4 2
3 2
1 2
2 5
Sample Output
2
题目大意:输入N,M,N代表有个牛,M代表有M种关系【前者可以打败后者】,问你这其中有几头牛的地位已经确定了。
题解思路:如果一头牛的地位确定,那么他必定与其他的n-1头的关系确定。也就是说他可以战胜x头牛,战败y头,&&x+y=n-1。根据这个思路的话,我们可以用一个mp数组记录关系,mp[a][b]=1,代表a能打败b,那么如果要判断a牛可不可以确定地位,那么只需要 统计mp[i][a]->能打败a的与mp[a][i]->a能打败的数量加起来够不够n-1即可。
难点:a能打败b,b能打败c,那a绝对可以打败c,那这种关系输入里没有给出怎么办呢?这里就需要这次我们需要的算法-Floyd传递闭包,大白话传递关系算法。你们肯定还想着Floyd算法,其实一样,遍历每一个经过点就可以了。
void Folyd(int n)
{
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
if(mp[k][i]&&mp[i][j]) mp[k][j]=1;
}
经过这样一个遍历,所有的关系也就都在了mp数组里面,但我们也可以看到这个时间复杂度:O(n^2),是有点吓人的,不过还好这个题的数据较少,(我也菜,也不会什么优化做法,以后遇到题目再总结好咯。)
最后附一下这个题的AC代码:
#include <queue>
#include <cstdio>
#include <stdlib.h>
#include <string.h>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const int INF=1e9;
int mp[120][120];
int sum[200];
void addedge(int u,int v)
{
mp[u][v]=1;
}
void Folyd(int n)
{
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
if(mp[k][i]&&mp[i][j]) mp[k][j]=1;
}
void restart()
{
memset(mp,0,sizeof(mp));
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
restart();
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
}
Folyd(n);
int sum1=0;
for(int i=1;i<=n;i++)
{
sum1=0;
for(int k=1;k<=n;k++)
{
if(i==k) continue;
sum1+=mp[i][k];
sum1+=mp[k][i];
}
sum[i]=sum1;
}
int ans=0;
for(int i=1;i<=n;i++)
if(sum[i]==n-1)
ans++;
cout<<ans<<endl;
}
return 0;
}