[是题解哦] 洛谷 P1536 村村通
题目链接
题目描述
某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府“村村通工程”的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?
输入输出格式
输入格式:
每个输入文件包含若干组测试测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目N(N<1000)和道路数目M;随后的M行对应M条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从1到N编号。
注意:两个城市间可以有多条道路相通。例如:3 3 1 2 1 2 2 1这组数据也是合法的。
当N为0时,输入结束。
输出格式:
对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。
题解
这道题我大概有两种思路。
- 并查集求集合个数
- Tarjan求强连通分量个数
并查集
我们可以考虑使用并查集建立集合。
由题目可获得n棵树,要想所有村庄都联通,需要这n棵树相连,这n棵树相连最少需要n-1条边。
Tarjan
由题目可知图中存在n个联通块。
由无向图可知联通块均为强连通分量。
Tarjan算法的思路和并查集差不多,求出强连通分量的个数n,这n个强连通分量联通需要n-1条边。
但是我懒得写Tarjan。
代码
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 int n,m; 6 int f[2010]; 7 8 inline int find(int k){ 9 return f[k]==k?k:f[k]=find(f[k]); 10 } 11 12 void unionn(int x,int y){ 13 x=find(x); 14 y=find(y); 15 f[x]=y; 16 } 17 18 int main(){ 19 scanf("%d",&n); 20 while(n!=0){ 21 scanf("%d",&m); 22 for(int i=1;i<=n;i++) 23 f[i]=i; 24 for(int i=1;i<=m;i++){ 25 register int u,v; 26 scanf("%d%d",&u,&v); 27 u=find(u); 28 v=find(v); 29 if(u!=v) 30 unionn(u,v); 31 } 32 int ans=0; 33 for(int i=1;i<=n;i++) 34 if(f[i]==i) //如果自己的父亲是自己,就存在一个集合 35 ans++; 36 printf("%d\n",ans-1); 37 scanf("%d",&n); 38 } 39 return 0; 40 }
友情链接:安利一只小姐姐的博客