codevs 2604 舞会邀请

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

 

额。。看了大爷的博客,发现其实用for循环就能搞定。。。(for循环大法吼啊)。

我当初想复杂了,用了比较复杂的方法,然而也能做??(跑的还挺快??)

我的方法是这样的,由于每一个人都需要被通知到,所以必定我们至少要通知那些入度为0的点(否则他们就永远通知不到了),在来贪心的考虑一下,那些入度不为0的点必定会被别人通知(也就是不需要主动通知),所以我们直接统计入度为0的点的个数就行了。

行了??这样有缺陷,环怎么办?一个环内入度均不为0,但也不代表不需要被通知,怎么办?我的想法很简单:tarjan缩点,统计缩点后的新点的入度为0的个数(因为缩点之后的图就是DAG了,DAG无后效性,所以必然答案就是入度为0的点)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int N=200+5;
const int M=19900+5;
inline int read()
{
    int ret=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9')
    {ret=ret*10+c-'0';c=getchar();}
    return ret*f;
}
int n;
struct edge{
    int from,to;
}e[M<<1];
int head[N],nxt[M<<1],tot=0;
inline void adde(int f,int t)
{
    e[++tot]=(edge){f,t};
    nxt[tot]=head[f];
    head[f]=tot;
}
int dfn[N],low[N],scc[N],tim=0,snum=0;
stack<int> s;
void tarjan(int x)
{
    dfn[x]=low[x]=++tim;
    s.push(x);
    for(int i=head[x];i;i=nxt[i])
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[v],low[x]);
        }
        else if(!scc[v])
        {
            low[x]=min(dfn[v],low[x]);
        }
    }
    if(dfn[x]==low[x])
    {
        snum++;
        while(true)
        {
            int u=s.top();
            s.pop();
            scc[u]=snum;
            if(u==x) break;
        }
    }
}
int rd[N];
void construct()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=nxt[j])
        {
            int v=e[j].to;
            if(scc[i]!=scc[v]) rd[scc[v]]++;
        }
    }
}
int main()
{
    n=read();
    int x;
    for(int i=1;i<=n;i++)
    {
        while(true)
        {
            x=read();
            if(!x) break;
            adde(i,x);
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i);
    }
    construct();
    int ans=0;
    for(int i=1;i<=snum;i++)
        if(!rd[i]) ans++;
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2017-11-02 18:58  Frank喵^_^  阅读(187)  评论(0编辑  收藏  举报