并查集是一种树型的数据结构,用于处理不相交集合的合并和查询问题,速度很快,有很多应用,其中kruskal算法最为广泛。
1),makeSet():
初始化每一个元素都各自为一个独立的集合,可以让每个元素的最高祖先为自身(parent[x] = x)。2),findSet(x):
找到元素x所处在集合的最高祖先,这也是判断两个元素x和y是否在同一个集合中的主要依据。并且在寻找x的最高祖先的时候沿途遇到的元素也将会找到其最高祖先(见后后面路劲压缩详解)。
3),unionSet(x, y):
将元素x和y所在的集合进行合并(最高祖先之间的变更,见下面,谁集合谁其实都一样),利用findSet()判断x和y所在的集合是否相同,如果不同,则要把其中一个元素所处在集合的最高祖先指向另一个元素所处在集合的最高祖先。
如果查找b的祖先,需要沿着b -> h -> c -> f这条路径一直向上爬,是一个O(n)的时间复杂度,这就引出了路径压缩优化。就是在findSet的时候利用递归顺便把经过的点的祖先直接修改成最高祖先。比如下图执行过findSet(a)之后就可以将b和c的祖先修改成d,下次再查找的时候就不用慢慢向上爬了。
下面给出C++的一个UFSet的一个类的具体代码。这里的代码没有考虑集合之间的大小关系,就是直接合并集合,随着问题的讨论的深入会逐渐添加内容,使之丰富
class UFSet
{
public:
UFSet(int nsize)
{
size = nsize;
parent = new int[size];
};
~UFSet()
{
delete[] parent;
parent = NULL;
};
void makeSet(int n);////初始化每个元素的祖先为自身
int findSet(int x);//找到元素x的祖先元素
void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
int getSets(int n);//获取集合数量
private:
int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
int size;
};
void UFSet::makeSet(int n) //初始化
{
//初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
//找到元素所在的集合,也就是找到自己的最高的祖先,
//这也是判断两个元素是否在同一个集合中的主要依据。
if (parent[x] == x)
return x;
parent[x] = findSet(parent[x]);//找到祖先,而不是父节点
return parent[x];
}
void UFSet::unionSet(int x, int y)
{
//将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,
//如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。
int ux = findSet(x);//获取节点x的祖先
int uy = findSet(y);
if (ux != uy)
parent[ux] = uy;
}
假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。
假如:n = 5 , m = 3 , r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。
输入包含多个测试用例,每个测试用例的第一行包含两个正整数 n、m,1=
对应每个测试用例,输出在这n个人里一共有多少个朋友圈。
5 3 1 2 2 3 4 5 3 3 1 2 1 3 2 3 0
2 1
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include "map"
#include
using namespace std;
#define MAX 100
class UFSet
{
public:
UFSet()
{
parent = new int[MAX];
};
~UFSet()
{
delete[] parent;
parent = NULL;
};
void makeSet(int n);////初始化每个元素的祖先
int findSet(int x);//找到元素x的祖先元素
void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
int getSets(int n);//获取集合数量
private:
int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
};
void UFSet::makeSet(int n) //初始化
{
//初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
//找到元素所在的集合,也就是找到自己的最高的祖先,
//这也是判断两个元素是否在同一个集合中的主要依据。
if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身)
return x;
parent[x] = findSet(parent[x]);//递归,最终找到x的最高祖先,并且沿途找到所有的最高祖先
return parent[x];
}
void UFSet::unionSet(int x, int y)
{
//将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,
//如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。
int ux = findSet(x);//获取节点x的祖先
int uy = findSet(y);
if (ux != uy) parent[ux] = uy;
}
int UFSet::getSets(int n)
{
int count = 0;
for (int i = 1; i <= n; i++)
{//如果存在某一个节点的祖先是自身说明他是孤立的或者本身就是祖先
//其他一切情况说明在某一个集合中,只有最高祖先才能拥有以自己为祖先的能力
if (parent[i] == i)
count++;
}
return count;
}
int main()
{
int m, n;
while (cin >> n )
{
if (n == 0) break;
cin >> m;
if (m >= MAX) break;
UFSet uset;
uset.makeSet(n);//初始化
//接收m对关系
int x = 0;
int y = 0;
for (int i = 0; i> x >> y;//注:这里数组下标代表人的对应编号
uset.unionSet(x, y);
}
cout << uset.getSets(n) << endl;
}
return 0;
}
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
对每个测试用例,在1行里输出最少还需要建设的道路数目。
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
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class UFSet
{
public:
UFSet(int nsize)
{
size = nsize;
parent = new int[size];
};
~UFSet()
{
delete[] parent;
parent = NULL;
};
void makeSet(int n);////初始化每个元素的祖先为自身
int findSet(int x);//找到元素x的祖先元素parent[x]
void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
int getSets(int n);//获取独立的集合数量
private:
int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
int size;
};
void UFSet::makeSet(int n) //初始化
{
//初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
//找到元素所在的集合,也就是找到自己的最高的祖先,
//这也是判断两个元素是否在同一个集合中的主要依据。
if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身)
return x;
parent[x] = findSet(parent[x]);//递归,最终找到x的最高祖先,并且沿途找到所有的最高祖先
return parent[x];
}
void UFSet::unionSet(int x, int y)
{
//将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,
//如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。
int ux = findSet(x);//获取节点x的祖先
int uy = findSet(y);
if (ux != uy)
parent[ux] = uy;
}
int UFSet::getSets(int n)
{
int count = 0;
for (int i = 1; i <= n; i++)
{//如果存在某一个节点的祖先是自身说明他是孤立的
if (parent[i] == i)
count++;
}
return count;
}
int main()
{
int m, n;
while (cin >> n >> m)
{
UFSet uset(100);
uset.makeSet(n);//初始化
//接收m对已经联通的城镇
int x = 0, y = 0;
for (int i = 0; i> x >> y;//注:这里数组下标位置代表城镇编号
uset.unionSet(x, y);
}
cout << uset.getSets(n)-1 << endl;//两个独立的几何只需要一条路
}
return 0;
}
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
对每个测试用例,在1行里输出最小的公路总长度。
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
3 5
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class Edge
{
public:
int acity;//城市a
int bcity;//城市b
int cost; //建成a到b的路的花费
bool operator < (const Edge &q) const//注意返回值的类型,运算符重载。
{
return cost> n, n > 0)
{
int m = n*(n - 1) / 2;
UFSet uset(100);
uset.makeSet(n);//初始化每个城市的祖先为自身
for (int i = 0; i < m; i++)
cin >> edge[i].acity >> edge[i].bcity >> edge[i].cost;
int mincost = uset.getMinCost(m);
cout << mincost << endl;
}
return 0;
}
/**************************************************************
Problem: 1017
User: EbowTang
Language: C++
Result: Accepted
Time:30 ms
Memory:1636 kb
****************************************************************/
3 1 2 1 0 1 3 2 0 2 3 4 0 3 1 2 1 0 1 3 2 0 2 3 4 1 3 1 2 1 0 1 3 2 1 2 3 4 1 0
3 1 0
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class Edge
{
public:
int acity;//城市a
int bcity;//城市b
int cost; //建成a到b的路的花费
bool isBuild; //标记路是否建成
bool operator < (const Edge &q) const//注意返回值的类型,运算符重载。
{
return cost> n, n > 0)
{
int m = n*(n - 1) / 2;
UFSet uset(100);
uset.makeSet(n);//初始化每个城市的祖先为自身
for (int i = 0; i < m; i++)
{
cin>> edge[i].acity>> edge[i].bcity>> edge[i].cost>> edge[i].isBuild;
if (edge[i].isBuild == 1)
uset.unionSet(edge[i].acity, edge[i].bcity);//将已经建成的两个城市编号建立连接
}
int mincost = uset.getMinCost(m);
cout << mincost << endl;
}
return 0;
}
It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.
For example, if we have 3 cities and 2 highways connecting city1-city2 and city1-city3. Then if city1 is occupied by the enemy, we must have 1 highway repaired, that is the highway city2-city3.
Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.
For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.
3 2 3 1 2 1 3 1 2 3
1 0 0
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class UFSet
{
public:
UFSet(int nsize)
{
size = nsize;
parent = new int[size];
};
~UFSet()
{
delete[] parent;
parent = NULL;
};
void makeSet(int n);////初始化每个元素的祖先为自身
int findSet(int x);//找到元素x的祖先元素parent[x]
void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
int getSets(int n);//获取独立的集合数量
private:
int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
int size;
};
void UFSet::makeSet(int n)
{
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
if (parent[x] == x)
return x;
parent[x] = findSet(parent[x]);
return parent[x];
}
void UFSet::unionSet(int x, int y)
{
int ux = findSet(x);
int uy = findSet(y);
if (ux != uy)
parent[ux] = uy;
}
int UFSet::getSets(int n)
{
int count = 0;
for (int i = 1; i <= n; i++)
{//如果存在某一个节点的祖先是自身说明他是孤立的
if (parent[i] == i)
count++;
}
return count;
}
int main()
{
int N = 0, M = 0, K = 0;
while (cin >> N >> M >> K)
{
UFSet uset(10000);
//接收m对已经联通的城市
vector xvec(M,0), yvec(M,0);
for (int i = 0; i> xvec[i] >> yvec[i];
vector vec(K,0);
for (int i = 0; i < K; i++)
cin >> vec[i];
for (int i = 0; i < K; i++)
{
uset.makeSet(N);//初始化
for (int j = 0; j < M; j++)
{
if (vec[i] != xvec[j] && vec[i] != yvec[j])//如果这个城市被占领,就不要建立连接了。模拟切断
uset.unionSet(xvec[j], yvec[j]);
}
int highways = uset.getSets(N) - 2;//为什么是2?去除被占城市,并且两个独立的集合修一条路
cout << highways << endl;
}
}
return 0;
}
/**************************************************************
Problem: 1325
User: EbowTang
Language: C++
Result: Accepted
Time:490 ms
Memory:5416 kb
****************************************************************/
现在有孤岛n个,孤岛从1开始标序一直到n,有道路m条(道路是双向的,如果有多条道路连通岛屿i,j则选择最短的那条),请你求出能够让所有孤岛都连通的最小道路总长度。
数据有多组输入。
每组第一行输入n(1<=n<=1000),m(0<=m<=10000)。
接着m行,每行输入一条道路i j d(0<=d<=1000),(i,j表示岛屿序号,d表示道路长度)。
对每组输入输出一行,如果能连通,输出能连通所有岛屿的最小道路长度,否则请输出字符串"no"。
3 5 1 2 2 1 2 1 2 3 5 1 3 3 3 1 2 4 2 1 2 3 3 4 1
3 no
#include
#include
#include
#include "queue"
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class Edge
{
public:
Edge()
{
dst = 1000000;
}
int acity;//岛屿a
int bcity;//岛屿b
int dst; //岛屿a到b的距离
};
Edge edge[100];
bool cmp(Edge mode1, Edge mode2)
{
return mode1.dst < mode2.dst;
}
class UFSet
{
public:
UFSet(int nsize)
{
size = nsize;
parent = new int[size + 1];
}
~UFSet()
{
delete[] parent;
parent = NULL;
}
// 初始化每个元素的祖先 为自身
void makeSet(int n);
// 找到元素x的祖先元素
int findSet(int x);
// 获取最小生成数路劲
void getMinWay(int m, int n);
private:
int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
int size;
};
void UFSet::makeSet(int n) //初始化
{
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
if (parent[x] == x)
return x;
parent[x] = findSet(parent[x]);
return parent[x];
}
void UFSet::getMinWay(int m,int n)
{
sort(edge+1, edge + m+1,cmp);//必须先对边排序(根据边的修建费用),这样才能贪心的形成最小花费
int sum = 0;
int ct = 0;
for (int i = 1; i<=m; i++)
{
int baseA = findSet(edge[i].acity);//找到城市a的祖先
int baseB = findSet(edge[i].bcity);
if (baseA != baseB)
{
ct++;
parent[baseA] = baseB;
sum += edge[i].dst;
}
}
if (ct == n - 1)
printf("%d\n", sum);
else
printf("no\n");
}
int main()
{
int n = 0;//岛屿数目
int m = 0;//道路数目
while (cin >> n >> m)
{
UFSet uset(n);
uset.makeSet(n);//初始化每个城市的祖先为自身
int a = 0, b = 0, ndst = 0;
for (int i = 1; i <= m; i++)
{ //cin >> edge[i].acity >> edge[i].bcity >> edge[i].dst;
scanf("%d%d%d", &edge[i].acity, &edge[i].bcity, &edge[i].dst);
//麻痹,不是说好多条边联通两个岛屿时,选择最小的边么?麻痹!
//不应该这样么:
/*
int a = 0, b = 0, ndst = 0;
for (int i = 1; i <= m; i++)
{
cin >> a >> b >> ndst;
edge[i].acity = a;
edge[i].bcity = b;
if (edge[i].dst > ndst)
edge[i].dst = ndst;
}
*/
}
uset.getMinWay(m, n);
}
return 0;
}
给定一个无向图和其中的所有边,判断这个图是否所有顶点都是连通的。
每组数据的第一行是两个整数 n 和 m(0<=n<=1000)。n 表示图的顶点数目,m 表示图中边的数目。如果 n 为 0 表示输入结束。随后有 m 行数据,每行有两个值 x 和 y(0
对于每组输入数据,如果所有顶点都是连通的,输出"YES",否则输出"NO"。
4 3 1 2 2 3 3 2 3 2 1 2 2 3 0 0
NO YES
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class UFSet
{
public:
UFSet(int nsize)
{
parent = new int[nsize + 1];
}
~UFSet()
{
delete[] parent;
parent = NULL;
}
// 初始化每个顶点的祖先为自身
void makeSet(int n);
// 找到元素x的祖先顶点
int findSet(int x);
void unionSet(int x, int y);
int getSets(int n);
private:
int *parent;//存放祖先顶点,例如x=parent[i],元素i的祖先顶点为元素x
};
void UFSet::makeSet(int n) //初始化
{
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
if (parent[x] == x)
return x;
parent[x] = findSet(parent[x]);
return parent[x];
}
void UFSet::unionSet(int x, int y)
{
int ux = findSet(x);
int uy = findSet(y);
if (ux != uy)
parent[ux] = uy;
}
int UFSet::getSets(int n)
{
int count = 0;
for (int i = 1; i <= n; i++)
{//如果存在某一个顶点的祖先是自身说明他是孤立的或者本身就是祖先
if (parent[i] == i)
count++;
}
return count;
}
int main()
{
int n = 0, m = 0;
while (cin >> n >> m,n>0)
{
UFSet uset(n);
uset.makeSet(n);//初始化每个顶点(顶点编号为1到n)的祖先为自身
int avex = 0,bvex=0;
for (int i = 1; i <= m; i++)
{
cin >> avex >> bvex;
uset.unionSet(avex,bvex);
}
if (uset.getSets(n) == 1)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
/**************************************************************
Problem: 1109
User: EbowTang
Language: C++
Result: Accepted
Time:40 ms
Memory:1520 kb
****************************************************************/
已知一个无向带权图,求最小整数k。使仅使用权值小于等于k的边,节点1可以与节点n连通。
输入包含多组测试用例,每组测试用例的开头为一个整数n(1 <= n <= 10000),m(1 <= m <= 100000),代表该带权图的顶点个数,和边的个数。
接下去m行,描述图上边的信息,包括三个整数,a(1 <= a <= n),b(1 <= b <= n),c(1 <= c <= 1000000),表示连接顶点a和顶点b的无向边,其权值为c。
输出为一个整数k,若找不到一个整数满足条件,则输出-1。
3 3 1 3 5 1 2 3 2 3 2 3 2 1 2 3 2 3 5 3 1 1 2 3
3 5 -1
#include
#include
#include
#include "queue"
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class Edge
{
public:
Edge()
{
dst = 0;
}
int avex;
int bvex;
int dst;
bool operator <(const Edge &mode) const
{
return dst> n >> m)
{
UFSet uset(n);
uset.makeSet(n);//初始化每个城市的祖先为自身
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &edge[i].avex, &edge[i].bvex, &edge[i].dst);
uset.makeMST(m, n);
}
return 0;
}
/**************************************************************
Problem: 1545
User: EbowTang
Language: C++
Result: Accepted
Time:650 ms
Memory:2820 kb
****************************************************************/
3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100
3 ?
#include
#include
#include
#include "queue"
#include "vector"
#include "string"
#include "algorithm"
#include
#include "stack"
#include
#include
using namespace std;
class Edge
{
public:
Edge()
{
dst = 0;
}
int avex;
int bvex;
int dst;
bool operator <(const Edge &mode) const
{
return dst= nvex && getSets(nvex) == 1)
cout << minCost << endl;
else
cout << "?" << endl;
return minCost;
}
int UFSet::getSets(int nvex)
{
int count = 0;
for (int i = 1; i <= nvex; i++)
{//如果存在某一个节点的祖先是自身说明他是孤立的
if (parent[i] == i)
count++;
}
return count;
}
int main()
{
int nedge = 0;//边数
int nvex= 0;//顶点数
while (cin >> nedge >> nvex)
{
if (nedge == 0)
break;
UFSet uset(nvex);
uset.makeSet(nvex);//初始化每个城市的祖先为自身
for (int i = 1; i <= nedge; i++)
scanf("%d%d%d",&edge[i].avex, &edge[i].bvex, &edge[i].dst);
uset.getMinCost(nedge, nvex);
}
return 0;
}
/**************************************************************
Problem: 1024
User: EbowTang
Language: C++
Result: Accepted
Time:10 ms
Memory:1532 kb
****************************************************************/
3 3 1 2 1 3 2 3 3 2 1 2 2 3 0
1 0
#include "vector"
#include
using namespace std;
class Edge
{
public:
int aVex;//顶点a
int bVex;//顶点b
};
Edge edge[100000];
class UFSet
{
public:
UFSet(int nsize)
{
size = nsize;
parent = new int[size+1];
};
~UFSet()
{
delete[] parent;
parent = NULL;
};
void makeSet(int n);////初始化每个元素的祖先为自身
int findSet(int x);//找到元素x的祖先元素
void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
int getSets(int n);//获取集合数量
private:
int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
int size;
};
void UFSet::makeSet(int n) //初始化
{
//初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身
for (size_t i = 1; i <= n; i++)
parent[i] = i;
}
int UFSet::findSet(int x)
{
//找到元素所在的集合,也就是找到自己的最高的祖先,
//这也是判断两个元素是否在同一个集合中的主要依据。
if (parent[x] == x)
return x;
parent[x] = findSet(parent[x]);//找到祖先,而不是父节点
return parent[x];
}
void UFSet::unionSet(int x, int y)
{
//将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,
//如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。
int ux = findSet(x);//获取节点x的祖先
int uy = findSet(y);
if (ux != uy)
parent[ux] = uy;
}
int UFSet::getSets(int n)//获取集合数量
{
int count = 0;
for (int i = 1; i <= n; i++)
{
if (parent[i] == i)
count++;
}
return count;
}
int main()
{
int nVex = 0;
int mEdge = 0;
while (cin >> nVex >> mEdge,nVex>0)
{
UFSet uset(nVex);
uset.makeSet(nVex);
vector vecdegree(nVex+1,0);
for (int i = 0; i < mEdge; i++)
{
cin >> edge[i].aVex >> edge[i].bVex;
vecdegree[edge[i].aVex]++;
vecdegree[edge[i].bVex]++;
uset.unionSet(edge[i].aVex,edge[i].bVex);
}
bool flag = true;
for (int i = 1; i <= nVex; i++)
{
if (vecdegree[i] % 2 != 0)//每个度必须为偶数
{
flag = false;
break;
}
}
if (flag && uset.getSets(nVex) == 1)//必须只有一个集合,即所有点相互可达
cout << "1" << endl;
else
cout << "0" << endl;
}
return 0;
}
/**************************************************************
Problem: 1027
User: EbowTang
Language: C++
Result: Accepted
Time:130 ms
Memory:2300 kb
****************************************************************/
【1】作者:Dong | 新浪微博:西成懂 | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明
网址:http://dongxicheng.org/structure/union-find-set/
本博客的文章集合:http://dongxicheng.org/recommend/
【2】九度OJ,http://ac.jobdu.com/problem.php?pid=1526