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; }