并查集:将编号分别为1到n的n个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。主要有两个操作:(1)合并两个集合,(2)查找某元素属于哪个集合。下面是利用并查集求解Hdu 1232 畅通工程(http://acm.hdu.edu.cn/showproblem.php?pid=1232),比用dfs,bfs搜索大大提高了时间效率。
#include <iostream>
#include <vector>
using namespace std;
vector <int> parents;
int findSet(int i)//if (parents[i]==i) then i is root;else if (parents[i]==j(j!=i)) then j is root.
{
int root=i;
while(root != parents[root]) //after loop get root
{
root=parents[root];
}
int k=i;
while(k != root) //path compression
{
int t=parents[k];
parents[k]=root;
k=t;
}
return root;
}
void unionSet(int a, int b)//union a,b to the small parent
{
int j=findSet(a);
int k=findSet(b);
if (j==k) return;
if (j<k)
{
parents[k]=j;
}
else
{
parents[j]=k;
}
}
bool run()
{
int n,m,i;
cin>>n;
if (n==0) return false;
cin>>m;
parents.resize(n+1);
for(i=1;i<=n;i++)
{
parents[i]=i; //init ,each i is a tree
}
for(i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
unionSet(a,b);
}
int cntRoot=0;
for(i=1;i<=n;i++)
{
if (i==parents[i]) //count subtrees
{
cntRoot++;
}
}
cout << cntRoot-1 << endl;
return true;
}
int main()
{
while(run());
return 0;
}
说明:while(k != root) //把i开始结点的根修改为找到的根root,路径压缩便于提高效率