codevs 2604 舞会邀请(tarjan缩点BFS)

来源:互联网 发布:专业汽车维修软件 编辑:程序博客网 时间:2024/06/05 22:42

题目描述 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

题解:

#include<iostream>#include<cstdio>#include<stack>#include<queue>using namespace std;const int maxn=10000;struct cc{    int from,to;}es[maxn];int first[maxn],nxt[maxn];bool vis[maxn];int tot=0;void build(int ff,int tt){    es[++tot]=(cc){ff,tt};    nxt[tot]=first[ff];    first[ff]=tot;}int low[maxn],dfn[maxn];stack<int>s;int scc_num[maxn];int scc_cnt,cnt;int dfs(int u){    low[u]=dfn[u]=++cnt;    s.push(u);    for(int i=first[u];i;i=nxt[i])    {        int v=es[i].to;        if(!dfn[v])        {            low[v]=dfs(v);            low[u]=min(low[u],low[v]);        }        else if(!scc_num[v])        {            low[u]=min(low[u],dfn[v]);        }    }    if(low[u]==dfn[u])    {        scc_cnt++;        while(!s.empty())        {             int v=s.top(); s.pop();             scc_num[v]=scc_cnt;             if(u==v)             {                break;             }        }    }    return low[u];}int ru[maxn];queue<int>q;void bfs(int s){    q.push(s);    while(!q.empty())    {        int u=q.front(); q.pop();        for(int i=first[u];i;i=nxt[i])        {            int v=es[i].to;            if(!vis[v])            {                q.push(v);                vis[v]=1;            }        }    }}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        int x;        while(scanf("%d",&x))        {            if(x==0)            {                break;            }            build(i,x);        }    }    for(int i=1;i<=n;i++)    {        if(!dfn[i])        {            dfs(i);        }    }    for(int i=1;i<=n;i++)    {        for(int j=first[i];j;j=nxt[j])        {            int v=es[j].to;            if(scc_num[i]!=scc_num[v])            {                ru[scc_num[v]]++;            }        }    }    int ans=0;    for(int i=1;i<=n;i++)    {        if(!ru[scc_num[i]]&&!vis[i])//从入度为零的点开始搜        {            ans++;            vis[i]=1;            bfs(i);             }    }    printf("%d",ans);    return 0;}
原创粉丝点击