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的值。
思路
floyed求联通路径,然后将一个联通路径缩成一个点。
然后寻找入度为零的点,其数量就是答案。
#include<cstdio>
int n,k,a[201][201],b[201],f[201],ans=0,t=0;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){ //输入
scanf("%d",&k);
while(k!=0){
a[i][k]=1;
scanf("%d",&k);
}
}
for(int k=1;k<=n;++k) //floyed
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(k==i||i==j||j==k) continue;
if(a[i][k]&&a[k][j]) a[i][j]=1; //联通
}
for(int i=1;i<=n;++i) //缩点
if(b[i]==0){
++t;
b[i]=t; //t号点
for(int j=1;j<=n;++j)
if(a[i][j]&&a[j][i])
b[j]=t; //同为t号点
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(a[i][j]&&b[i]!=b[j]) f[b[j]]++;
//如果可以过去且不是同一个缩后的点,入度+
for(int i=1;i<=t;++i)
if(f[i]==0) ans++; //入度为0
printf("%d",ans); //输出。
}