最近刷的图论题,样式变化太多,很多都很难想到,比如说这个题,又学到了一种方法:传递闭包

 

用大白话来说,就是关系的传递。

 

看一下题目

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 ≤ AN; 1 ≤ BN; AB), 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;
}