codevs 舞会邀请(Tarjan)

来源:互联网 发布:最新淘宝客服用语大全 编辑:程序博客网 时间:2024/06/01 10:33

题目描述 Description
Smart是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。

Smart准备邀请n个已经确定的人,可是问题来了:

这n个人每一个人都有一个小花名册,名册里面写着他能够通知到的人的名字。比如说在A的人名单里写了B,那么表示A能够通知到B;但是B的名单里不见得有A,也就是说B不见得能够通知到A。

Smart觉得需要确定自己需要通知到多少个人(人数m),能够实际将所有n个人都通知到。并求出一种方案以确定m的最小值是多少。

注意:自己的名单里面不会有自己的名字。

输入描述 Input Description
第一行一个数n(1≤n≤200)。接下来n行,第i+1行表示编号为i的人的小花名册名单,名单以0结束。

输出描述 Output Description 一个整数,即m的值。

样例输入 Sample Input 5 1

2 0

1 3 0

0

0

1 0

样例输出 Sample Output 2

数据范围及提示 Data Size & Hint 1≤n≤200

这题数据范围很小,所以有很多做法。也有借助floyd的思想AC的。比如大爷http://blog.csdn.net/qq_36509464/article/details/52973913。这题可以看做Tarjan缩点来做。对于每个强连通分量求一下它的入度。我们只需要找最后出现多少个入度为0的强连通分量就是答案。
代码如下:

#include<iostream>#include<cstdio>#include<cstdlib>using namespace std;const int maxn=200005;struct dqs{    int f,t;}hh[maxn];int first[maxn],next[maxn];int tot=0; void build(int f,int t){    hh[++tot]=(dqs){f,t};    next[tot]=first[f];    first[f]=tot;}int read(){    int num=0;    char c;    c=getchar();    while(c<'0'||c>'9')        c=getchar();       while('0'<=c&&c<='9')    {        num=num*10+c-'0';        c=getchar();    }    return num;}int dfn[maxn],low[maxn],stack[maxn],jlqlt[maxn],du[maxn];bool in_stack[maxn];int cnt=0,snum=0,ttot=0;void group(int x){    dfn[x]=low[x]=++ttot;    stack[++snum]=x;    in_stack[x]=1;    for(int i=first[x];i;i=next[i])    {        int u=hh[i].t;        if(!dfn[u])        {            group(u);            low[x]=min(low[x],low[u]);                  }        else if(in_stack[u]) low[x]=min(low[x],dfn[u]);    }    if(dfn[x]==low[x])    {        cnt++;        while(true)        {            jlqlt[stack[snum]]=cnt;            in_stack[stack[snum]]=0;            snum--;            if(stack[snum+1]==x) break;        }    }}int main(){    int n,s;    n=read();    for(int i=1;i<=n;i++)    {        while(true)        {            s=read();            if(s==0) break;            build(i,s);        }    }    for(int i=1;i<=n;i++)   if(!dfn[i]) group(i);    for(int i=1;i<=n;i++)    {        for(int j=first[i];j;j=next[j])        {            int u=hh[j].t;            if(jlqlt[i]!=jlqlt[u])            {                du[jlqlt[u]]++;            }        }    }    int ans=0;    for(int i=1;i<=cnt;i++)        if(!du[i]) ans++;    printf("%d\n",ans);    return 0;}/*52 01 3 0001 0*/
原创粉丝点击