题解 P2419 【[USACO08JAN]牛大赛Cow Contest】

看到许多大佬都用了拓补排序,本蒟蒻偏不用这么高级的算法,其实这道题目用dfs就可以过了。(ps:对本题解有疑惑的person可以向我留下评论)

思路:

我们先来考虑一下怎么样我们才可以确定一个牛的排名,我们如果假设赢了或间接赢了这个牛的牛数为sum_win,输了或间接输掉的牛数为sum_lose,如果要确认一个牛的排名,很显然当且仅当满足一下情况的时候才能确定一个牛的排名。

sum_win+sum_lose==n-1

接下来这样的问题就转换为了如何求sum_win与sum_lose。
我们用两个图用来存这道题目中的输赢关系,其中第一个图我们用一个结点指向另一个结点表示一头牛输给了别人,另外一个图恰好相反。这样我们从1~n枚举结点i,从一个结点i开始dfs一遍第一个图,sum_win就是遍历到的结点数,这样也很完美地解决了间接赢了别人如何处理的问题,之后我们再遍历第二个图,累计遍历到的点,得到sum_lose
之后判断一下上面给出的条件即可得到第i个结点即牛是否满足条件

代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e2+5;

int n,m;
int vis_win[N];
int vis_lose[N];
int sum_win,sum_lose;
vector <int> win_graph[N];
vector <int> lose_graph[N];

void add(int x,int y){ //x为胜者
    win_graph[y].push_back(x);
    lose_graph[x].push_back(y);
}

void dfs_win(int x){
    vector <int> :: iterator it;
    for(it=win_graph[x].begin();it!=win_graph[x].end();it++){
        if(vis_win[*it]==0){
            sum_win++;
            vis_win[*it]=1;
            dfs_win(*it);
        }
    }
}

void dfs_lose(int x){
    vector <int> :: iterator it;
    for(it=lose_graph[x].begin();it!=lose_graph[x].end();it++){
        if(vis_lose[*it]==0){
            sum_lose++;
            vis_lose[*it]=1;
            dfs_lose(*it);
        }
    }
}

int main(){
    
    scanf("%d%d",&n,&m);
    int temp_x,temp_y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&temp_x,&temp_y);
        add(temp_x,temp_y);
    }
    
    int ans=0;
    for(int i=1;i<=n;i++){
        memset(vis_win,0,sizeof(vis_win));
        memset(vis_lose,0,sizeof(vis_lose));
        sum_win=0;sum_lose=0;
        dfs_win(i);
        dfs_lose(i);
        if(sum_win+sum_lose==n-1) ans++;
    }
    
    printf("%d\n",ans);
    
    return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/lixiao189/p/9300884.html
今日推荐