zoukankan      html  css  js  c++  java
  • BZOJ1051:受欢迎的牛(并查集 / Tarjan)

    1051: [HAOI2006]受欢迎的牛

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 8161  Solved: 4460

    Description

    每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

    Input

    第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)

    Output

    一个数,即有多少头牛被所有的牛认为是受欢迎的。

    Sample Input

    3 3

    1 2

    2 1

    2 3

    Sample Output

    1

    HINT

    100%的数据N<=10000,M<=50000
     
    题解:
    这题一开始我用并查集乱搞了一下,结果搞出来了...
    如果一头牛受欢迎,那么他所有喜欢的牛都是被所有牛认为受欢迎的。那么我们关键就是找出第一头被所有牛认为受欢迎的牛。
    在合并集合的时候用sum数组维护喜欢父亲结点的个数,当个数等于n时我们就找到一头牛了。
    之后再用个bfs来求就好了。
     
    代码如下:
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <queue>
    using namespace std;
    
    const int N = 10005,M = 50005 ;
    int n,m,tot;
    int head[N],f[N],sum[N],vis[N];
    map<int,map<int,int> > mp;
    struct Edge{
        int u,v,next ;
    }e[M];
    void adde(int u,int v){
        e[++tot].u=u;e[tot].v=v;
        e[tot].next=head[u];
        head[u]=tot;
    }
    int find(int x){
        return f[x]==x ? f[x] : f[x]=find(f[x]);
    }
    int main(){
        cin>>n>>m;
        int st=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=N-5;i++) f[i]=i,sum[i]=1;
        for(int i=1,u,v;i<=m;i++){
            scanf("%d%d",&u,&v);
            if(!mp[u][v]){
                mp[u][v]=1;
                adde(u,v);
                int fx=find(u),fy=find(v);
                if(fx!=fy){
                    f[fx]=fy;
                    sum[fy]+=sum[fx];
                    if(sum[fy]==n) st=fy;
                }
            }
        }
        int cnt =1;
        if(!st)puts("0");
        else{
            queue<int> q;
            q.push(st);vis[st]=1;
            while(!q.empty()){
                int u=q.front();q.pop();
                for(int i=head[u];i!=-1;i=e[i].next){
                    int v=e[i].v;
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                        cnt++;
                    }
                }
            }
            printf("%d
    ",cnt);
        }
        return 0;
    }
    View Code

    再来说一下tarjan。

    先用tarjan缩点,然后重新构图,找到出度为0的点那么这里面所有的牛都是被所有牛认为受欢迎的。

    注意一下构图后不连通的情况就好了。

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <stack>
    using namespace std;
    
    const int N = 10005 ,M = 50005 ;
    int n,m,tot,num,T;
    int head[N],dfn[N],low[N],vis[N],scc[N];
    struct Edge{
        int u,v,next ;
    }e[M];
    void adde(int u,int v){
        e[++tot].u=u;e[tot].v=v;
        e[tot].next=head[u];head[u]=tot ;
    }
    stack <int> s;
    void Tanjan(int u){
        dfn[u]=low[u]=++T;vis[u]=1;
        s.push(u);
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(!vis[v]){
                Tanjan(v);
                low[u]=min(low[u],low[v]);
            }else{
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            num++;int now;
            do{
                now = s.top();s.pop();
                scc[now]=num;
            }while(!s.empty() && now!=u);
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        for(int i=1,u,v;i<=m;i++){
            scanf("%d%d",&u,&v);
            adde(u,v);
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]) Tanjan(i);
        }
        int out[N]={0},in[N]={0};
        for(int u=1;u<=n;u++){
            for(int i=head[u];i!=-1;i=e[i].next){
                int v=e[i].v;
                if(scc[u]!=scc[v]){
                    out[scc[u]]++;
                    in[scc[v]]++;
                }
            }
        }
        int cnt=0,ans=0,tag;
        for(int i=1;i<=num;i++) if(!out[i]) cnt++,tag=i;     
        if(cnt==1){
            for(int i=1;i<=n;i++) if(scc[i]==tag) ans++;
            printf("%d",ans);
        }else puts("0");
        return 0;
    }
  • 相关阅读:
    Ubuntu 中软件的安装、卸载以及查看的方法总结
    无锁队列的环形数组实现
    Geodatabase模型
    地图投影与ArcGIS坐标系转换
    ARCGIS动态画点
    ArcEngine数据删除几种方法和性能比较
    AE开发技术文档--8种数据访问方法
    Hibernate 的HQL和sql有什么区别
    ActionContextCleanUp作用
    Hibernate延迟加载与opensessioninviewFilter
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10047728.html
Copyright © 2011-2022 走看看