畅通工程

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

Input

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。

Output

对每个测试用例,在1行里输出最少还需要建设的道路数目。

Sample

Input Output
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0 
 
1
0
2
998

   以上就是我们今天要讲的题目,看清楚了吧,是一道并查集的类型题,前几天刚刚讲了一个“并查集的基本操作”。

并查集的基本操作http://t.csdn.cn/bI0ae  因为以前讲过,所以我们今天就来运用我之前写的并查集的许多操作,有init初始化操作,insert插入函数,find查找加路径压缩函数,unionSet合并两个集合函数,print输出并查集函数。

  这道题,我们怎么运用呢?

  根据输入,首先输入了n,就将1到n内所有数字插入并查集中,现在并查集中每个数字都是一个集合,然后输入m组合并操作,每次进行unionSet(a,b)函数操作来合并,合并之后不要忘了运用find函数进行路径压缩算法。

  进行了这些操作之后,并查集里面有多个集合,如果只有一个集合那就代表不需要道路相连,只需要输出一个0即可,如果当前并查集有多个集合,就需要进行合并操作,首先,我们需要找到目前集合最大的那个集合的代表,然后将其他没有和这个代表相连的元素进行unionSet函数,千万别忘了find路径压缩,执行一次unionSet操作,就将sum++,相当于连了一条道路。

  就这样,这道题的基本思路就讲到这里了,我们来看代码。

畅通工程:

#include
using namespace std;
template
struct DisjointSet{
	int *parent;
	T *data;
	map m;
	int capacity;
	int size;
	DisjointSet(int max=10){
		capacity=max;
		size=0;
		parent=new int[max+1];
		data=new T[max+1];
	}
	~DisjointSet(){
		delete [] parent;
		delete [] data;
	}
	void init(int max){
		capacity=max;
		size=0;
		parent=new int[max+1];
		data=new T[max+1];
	}
	bool insert(T x){
		if(size==capacity) return false;
		size++;
		data[size]=x;
		parent[size]=-1;
		m[x]=size;
		return true;
	}
	int getIndex(T x){
		for(int i=1;i<=size;i++)
		  if(data[i]==x)
		    return i;
		return -1; 
	}
	int find(T x){
		typename map::iterator it;
		it=m.find(x);
		if(it==m.end()) return -1;
		int i,rt;
		i=rt=it->second;
		while(parent[rt]>0)
		  rt=parent[rt];
		int tmp;
		for(;i!=rt;i=tmp){
			tmp=parent[i];
			parent[i]=rt;
		}
		return rt;
	}
	void unionSet(T x,T y){
		int rx,ry;
		rx=find(x);
		ry=find(y);
		if(rx==-1||ry==-1) return ;
		if(rx==ry) return ;
		if(parent[rx] s;
	int n,m,sum;
	while(cin>>n){
		s.init(100);
		sum=0;
		if(n==0) return 0;
		for(int i=1;i<=n;i++) s.insert(i);
		cin>>m;
		for(int i=0;i>a>>b;
			s.unionSet(a,b);
		}
		if(m==0){
			cout<

   注意啊,我们需要很多个特判(就是用来判断如果是当前跟的话就直接跳过)!

今天就讲到这里了,等会儿我讲解第二道题。

该题链接:

畅通工程 - HDU 1232 - Virtual Judgehttps://vjudge.net/problem/HDU-1232#google_vignette畅通工程_第1张图片 

你可能感兴趣的:(算法,数据结构,C++,并查集,数据结构,算法,HDU)