[bzoj-1051] [HAOI2006]受欢迎的牛

7 篇文章 0 订阅

题目传送门
题意解析:其实就是题目意思,找出一个被所有奶牛认为是最受欢迎的奶牛,并且这种认为是具有传递性的,最后找出有多少只最受欢迎的奶牛。


My opinion:看到题目的时候感觉跟并查集很像,但是一想,一只奶牛可以不止认为另一只奶牛是受欢迎的,所以并查集直接被排除了。然后就马上想到了图论,可以在每一个关系中建立一条由奶牛指向被认为是受欢迎的奶牛。那么可能会存在环,环中的每一只奶牛都认为对方是受欢迎的。先考虑没有环的情况,很明显,如果一只奶牛认为另一只奶牛是受欢迎的,那么它就一定不是最受欢迎的奶牛,因为它认为受欢迎的奶牛不认为它是受欢迎的,那么形成了一个DAG图,所以最后出度为0的奶牛就是最受欢迎的奶牛,当然前提是没有多个连通块,因为有多个联通块的话,就一定没有奶牛会被所有得奶牛认为是受欢迎的。现在考虑有环的情况就很简单了,我们把环看成一个点就行了(就是缩个点就好了)。
总结:
1、建图。
2、缩点。
3、判断是否是多个连通块。
4、找出出度为0的点。


不要问我为什么是c++。
代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define sqr(x) (x)*(x)
#define ll long long
#define db double
#define INF 200000000000000LL
#define eps 1e-8
using namespace std;
ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=10005,maxm=50005;
int n,m,len,num,top,Time;
int vet[maxm],Next[maxm],head[maxn];
int dfn[maxn],low[maxn],c[maxn],q[maxn];
int sum[maxn],edge[maxn];
void add(int u,int v){
    vet[++len]=v;
    Next[len]=head[u];
    head[u]=len;
}
void dfs(int u){
    dfn[u]=low[u]=++Time;
    q[++top]=u;
    for (int e=head[u];e;e=Next[e]){
        int v=vet[e];
        if (!dfn[v]){
            dfs(v);
            low[u]=min(low[v],low[u]);
        }else low[u]=min(dfn[v],low[u]);
    }
    if (dfn[u]==low[u]){
        num++;
        while (top&&q[top]!=u)
            c[q[top--]]=num;
        c[u]=num;
        top--;
    }
}
int main(){
    n=read(),m=read();
    rep(i,1,m){
        int u=read(),v=read();
        add(u,v);
    }
    num=top=0;
    rep(i,1,n)
        if (!dfn[i]) dfs(i);
    rep(i,1,n)
        sum[c[i]]++;
    rep(u,1,n)
        for (int e=head[u];e;e=Next[e]){
            int v=vet[e];
            if (c[u]!=c[v])
                edge[c[u]]++;
        }
    int ans=0,res=-1;
    rep(i,1,num)
        if (edge[i]==0){
            ans++;
            res=i;
        }
    if (ans==1) printf("%d\n",sum[res]);
        else puts("0");
    return 0;
}

附上AC记录:
不要问为什么是pascal
我翻译成c++的
我翻译成c++的
我翻译成c++的
(重要的事情说三遍)
好早以前写p的,最近这题又拉出来做了一遍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值