poj 2186 Popular Cows

题意:有n头牛,若A认为B是受欢迎的,那么B的人气+1,认为某头牛受欢迎是可以传递的。最后问有多少头牛的人气是n-1。

思路:先用tarjan求个强连通分量,可以得到一个DAG,则同一个强连通分量中的点相互认为对方受欢迎。然后选择所有入度为0的点,从这一点开始遍历,计算其子节点的人气,需要注意的是由于有横叉边,所以到某个节点直接从这个点往下搜是不对的,一个简单的方法就是计算到达这个点的次数,如果等于该点的入度,那么就往下搜,如果不等,就先“等”,一直到下次访问这个点。这题刚开始一看感觉挺水的,但是wa了好几次,刚开始是被题意坑了,后来又没有考虑到横叉边,真是桑心……

 

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=10000+10;
const int maxm=50000+10;
struct Edge
{
    int v,next;
};
Edge edges[maxm<<1],ee[maxm<<1];
int head[maxn],hh[maxn],nEdge,ne;
int pre[maxn],sccno[maxn],dfs_clock,scc_cnt;
int degree[maxn],d2[maxn],val[maxn],sup[maxn],maxsup;
stack<int>S;
void AddEdge(int u,int v)
{
    nEdge++;
    edges[nEdge].v=v;
    edges[nEdge].next=head[u];
    head[u]=nEdge;
}
void addedge(int u,int v)
{
    ne++;
    ee[ne].v=v;
    ee[ne].next=hh[u];
    hh[u]=ne;
}
void Init()
{
    memset(head,0xff,sizeof(head));
    memset(hh,0xff,sizeof(hh));
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));
    memset(degree,0,sizeof(degree));
    memset(sup,0,sizeof(sup));
    memset(val,0,sizeof(val));
    memset(d2,0,sizeof(d2));
    nEdge=ne=-1;
}
int tarjan(int u)
{
    int lowu=pre[u]=++dfs_clock;
    S.push(u);
    for(int k=head[u];k!=-1;k=edges[k].next)
    {
        int v=edges[k].v;
        if(!pre[v])
        {
            int lowv=tarjan(v);
            lowu=min(lowu,lowv);
        }
        else if(!sccno[v])
            lowu=min(lowu,pre[v]);
    }
    if(lowu==pre[u])
    {
        scc_cnt++;
        while(true)
        {
            int x=S.top();S.pop();
            sccno[x]=scc_cnt;
            if(x==u) break;
        }
    }
    return lowu;
}
void find_scc(int n)
{
    dfs_clock=scc_cnt=0;
    for(int i=1;i<=n;++i)
      if(!pre[i]) tarjan(i);
}
void dfs(int u)
{
    if(val[u]>1) sup[u]+=(val[u]-1);
    maxsup=max(maxsup,sup[u]);
    for(int k=hh[u];k!=-1;k=ee[k].next)
    {
        int v=ee[k].v;
        sup[v]+=sup[u]+1;
        d2[v]++;
        if(d2[v]==degree[v])
        dfs(v);
    }
}
void solve(int n)
{
    int v;
    for(int u=1;u<=n;++u)
    {
        val[sccno[u]]++;
        for(int k=head[u];k!=-1;k=edges[k].next)
        {
            v=edges[k].v;
            if(sccno[u]!=sccno[v])
            {
                addedge(sccno[u],sccno[v]);
                degree[sccno[v]]++;
            }
        }
    }
    maxsup=0;
    for(int i=1;i<=scc_cnt;++i)
      if(!degree[i]) dfs(i);
    if(maxsup!=n-1)
    {
        printf("0\n");
        return;
    }
    int cnt=0;
    for(int i=1;i<=n;++i)
    {
        if(sup[sccno[i]]==maxsup)
          cnt++;
    }
    printf("%d\n",cnt);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    Init();
    int u,v;
    for(int i=0;i<m;++i)
    {
        scanf("%d%d",&u,&v);
        AddEdge(u,v);
    }
    find_scc(n);
    solve(n);
    return 0;
}


 

你可能感兴趣的:(poj,图论)