[最短路-Floyd][并查集]SSL P2344 刻录光盘
Description
在PJOI2010夏令营快要结束的时候,很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家,以便大家回去后继续学习。组委会觉得这个主意不错!可是组委会一时没有足够的空光盘,没法保证每个人都能拿到刻录上资料的光盘,又来不及去买了,怎么办呢?
组委会把这个难题交给了DYJ,DYJ分析了一下所有营员的地域关系,发现有些营员是一个城市的,其实他们只需要一张就可以了,因为一个人呢拿到光盘以后,其他人可以拿着U盘之类的东西去拷贝啊!
可是DYJ调查后发现,有些营员并不是那么合作,他们愿意某一些人到他那儿拷贝资料,当然也可能不愿意让另外一些人到他那儿拷贝资料,这与我们PJOI宣扬的团队合作精神格格不入!
现在假设总共有N个营员(2<=N<=200),每个营员的编号为1~N。DJY给每个人发了一张调查表,让每个营员填上自己愿意让哪些人到他那儿拷贝资料。当然,如果A愿意把资料拷贝给B,而B又愿意把资料拷贝给C,则一旦A获得了资料,则B、C也会获得资料。
现在请你编写一个程序,根据回收上来的调查表,帮助DZY计算出组委会至少要刻录多少张光盘,才能保证所有营员回去后都能得到夏令营资料?
Input
先是一个数N,接下来N行,分别表示各个营员愿意把自己获得的资料拷贝给其他哪些营员。即输入数据的第N+1行表示第i个营员愿意把资料拷贝给那些营员编号,以一个0结束。如果一个营员不愿意拷贝资料给任何人,则相应的行只有1个0,一行中的若干数之间用一个空格隔开。
Output
一个正整数,表示最少要刻录的光盘数。
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
题解
- 题目其实就是让我们求有多少个联通块
- 那么其实我们将给出的边定为true
- 跑一遍Floyd,可以将可以达到的点全部跑出来
- 然后,将这些边打进并查集
- 最后求有多少个并查集
代码
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 int n,ans,f[210],v[210][210],a[210]; 5 void bing(int x,int y) 6 { 7 while (x!=f[x]) x=f[x]; 8 f[y]=x; 9 } 10 int getfather(int x) 11 { 12 while (x!=f[x]) x=f[x]; 13 return x; 14 } 15 int main() 16 { 17 scanf("%d",&n); 18 for (int i=1;i<=n;i++) f[i]=i; 19 for (int i=1;i<=n;i++) 20 { 21 int x; 22 scanf("%d",&x); 23 while (x!=0) 24 { 25 v[i][x]=true; 26 scanf("%d",&x); 27 } 28 } 29 for (int k=1;k<=n;k++) 30 for (int i=1;i<=n;i++) 31 for (int j=1;j<=n;j++) 32 v[i][j]=v[i][j]||v[i][k]&&v[k][j]; 33 for (int i=1;i<=n;i++) 34 for (int j=1;j<=n;j++) 35 if (v[i][j]) 36 bing(i,j); 37 for (int i=1;i<=n;i++) a[getfather(i)]=1; 38 for (int i=1;i<=n;i++) if (a[i]==1) ans++; 39 printf("%d",ans); 40 return 0; 41 }