JSK-习题:受欢迎的蒜头-Tarjan强连通分量+缩点 (POJ2186)

这里写图片描述

思路:

在有向无环图中,若任意点都能到达点A,那么有且仅有A点的出度为0,而题中可能包含环,通过缩环,构成新的有向无环图,若a欢迎b,则将a连向b,通过Taijan缩环模板处理,得到各点所在强连通分支,再通过出度判断,即可求解。

代码:

#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N=10005;
struct edge
{
    int to,next;
}e[5*MAX_N];
int p[MAX_N],eid;
void insert(int u,int v)
{
    e[eid].to=v;
    e[eid].next=p[u];
    p[u]=eid++;
}
int dfn[MAX_N],low[MAX_N];
int idx=0;
int belong[MAX_N],scc=0;
int s[MAX_N],top=0;
bool instack[MAX_N];
int out[MAX_N];
void init()
{
    eid=0;
    memset(p,-1,sizeof(p));
    memset(dfn,0,sizeof(dfn));               //一定要初始化为0,千万不能为-1......
    memset(low,0,sizeof(low));
    memset(instack,false,sizeof(instack));
    memset(belong,0,sizeof(belong));
    memset(out,0,sizeof(out));
}
void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    s[top++]=u;
    instack[u]=true;
    for(int i=p[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        ++scc;
        do
        {
            belong[s[--top]]=scc;
            instack[s[top]]=false;
        }
        while(s[top]!=u);
    }
}
int main()
{
    init();
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        insert(a,b);
    }
    for(int i=1;i<=n;i++)
        if(dfn[i]==0)
            tarjan(i);
    for(int i=1;i<=n;i++)
        for(int k=p[i];k!=-1;k=e[k].next)
    {
        if(belong[i]!=belong[e[k].to])            //统计新图点的出度,a到b,若a,b不在同一个新点中,则a所在新点出度++
            out[belong[i]]++;
    }
    int pos,tot=0;
    for(int i=1;i<=scc;i++)
    {
        if(out[i]==0)
        {
            tot++;
            pos=i;
        }
    }
    for(int i=1;i<=n;i++)             //若有不可达点,则一定不成立
        if(!belong[i])
            tot=0;
    if(tot==1)        //出度为0的点只能有一个,否则一定有人不欢迎另一人
    {
        int sum=0;
        for(int i=1;i<=n;i++)
            if(belong[i]==pos)         //统计该新点中点的个数
                sum++;
        cout<<sum<<endl;
    }
    else
        cout<<0<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43093481/article/details/82262869
今日推荐