HAOI2006受欢迎的牛

缩点裸题。

题目链接:http://poj.org/problem?id=2186

正确板子是 :1.缩点之后无需在意各连通块的大小,只需找出所有连通块都经过的那一个连通块;

       2.最后只需:有且仅有一个点(连通块)出度为0,则输出该点大小;其他情况一律输出0。

       (依据:①有向图缩点之后成为有向无环图;

           ②有向无环图中必有出度为0的点 + 若只有一个出度为0的点,则所有点都可到达该点;

           ③若有向无环图中有多个出度为0的点,则不存在 所有点都可到达的点。)

自己用的深搜找那个所有点都可到达的点,但有谜:为何是>=n?何时重复了?

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,x,y,xnt,nex[10005],rd[10005],cd[10005],dfn[10005],low[10005],sc[10005];
int tim,s,in[10005],cnt,col[10005],siz,gs[10005];
bool vis[10005],sid[10005][10005],flag[10005];
struct Node{
    int next,to,from;
}edge[50005];
void add(int x,int y)
{
    xnt++;
    edge[xnt].next=nex[x];
    edge[xnt].to=y;
    edge[xnt].from=x;
    nex[x]=xnt;
}
void tar(int a)
{
    for(int i=nex[a];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            dfn[v]=++tim;
            low[v]=dfn[v];
            vis[v]=1;
            in[++cnt]=v;
            tar(v);
            if(low[v]<low[a])
                low[a]=low[v];
        }
        else if(vis[v])
                  if(low[v]<low[a])low[a]=low[v];//找最早的 
    }
    if(dfn[a]==low[a])
    {
        siz++;
        int k=0;
        while(1)
        {
            k++;
            col[in[cnt]]=siz;
            vis[in[cnt]]=0;
            cnt--;
            if(in[cnt+1]==a)break;
        }
        sc[siz]=k;
        gs[siz]=k;
    }
}
void ser(int str,int zs)
{
    int k=zs;
    if(!flag[str])
    {
        flag[str]=1;
        zs+=sc[str];
    }
    sc[str]+=k;
    if(!cd[str])return;
    for(int i=1;i<=siz;i++)
        if(sid[str][i])ser(i,zs);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
        {
            cnt=1;
            dfn[i]=++tim;
            low[i]=dfn[i];
            vis[i]=1;
            in[1]=i;
            tar(i);
        }
    for(int i=1;i<=m;i++)
    {
        int u=edge[i].from;
        int v=edge[i].to;
        if(col[u]!=col[v])
        {
            sid[col[u]][col[v]]=1;//col[u]
            rd[col[v]]++;
            cd[col[u]]++;
        }
    }
    
//    for(int i=1;i<=siz;i++)//90  深搜
//        if(!rd[i])
//            ser(i,0);
//    for(int i=1;i<=siz;i++)
//        if(sc[i]>=n)    //由==改为>=则100 
//            s+=gs[i];
            
//    for(int i=1;i<=siz;i++)//85
//        if(!cd[i])s+=gs[i];

    int uu=0;int kk=0;//100  结论
    for(int i=1;i<=siz;i++)
        if(!cd[i])uu++,kk=i;
    if(uu==1)printf("%d",gs[kk]);
    else printf("0");

//    printf("%d",s);
    return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/8261689.html