题意:给n个人(n一定能被3整除),m行ai,bi,表示ai和bi必须要在一个团体里,问是否能够把这n个人分成n/3队,输出这n/3个集合。
思路:并查集归并每个集合,并且记录每个集合中元素的个数,有大于3的直接输出-1即可,vector记录当前集合中存在哪些元素;对于集合元素小于3的集合,去找其他集合合并,直到集合中元素的个数为3.
代码如下:
#include <bits/stdc++.h>
using namespace std;
int n,m,par[110],cnt[110],vis[110];
vector<int>vct[110];
int FindSet(int x){
if(x == par[x]) return x;
return par[x] = FindSet(par[x]);
}
void UnoinSet(int x, int y){
int fx = FindSet(x);
int fy = FindSet(y);
if(fx != fy) par[fx] = fy;
}
int main(){
scanf("%d%d",&n,&m);
int x,y;
for(int i = 1; i <= n; i ++) par[i] = i;
for(int i = 0; i < m; i ++){
scanf("%d%d",&x,&y);
UnoinSet(x,y);
}
for(int i = 1; i <= n; i ++){
x = FindSet(i);
cnt[x] ++;
vct[x].push_back(i);
}
int MaxValue = 0;
for(int i = 1; i <= n; i ++) MaxValue = max(MaxValue,cnt[i]);
if(MaxValue > 3) printf("-1\n");
else{
int flag = 1;
for(int i = n; i >= 1; i --){
if(!vis[i] && cnt[i] < 3 && cnt[i] > 0){
for(int j = i-1; j >= 1; j --){
if(!vis[j] && cnt[i] + cnt[j] <= 3){
cnt[i] += cnt[j]; vis[j] = 1;
for(int k = 0; k < vct[j].size(); k ++){
vct[i].push_back(vct[j][k]);
}
}
}
if(cnt[i] != 3){
flag = 0; break;
}
}
}
if(!flag) printf("-1\n");
else{
for(int i = 1; i <= n ;i ++){
if(cnt[i] == 3){
for(int j = 0; j < vct[i].size(); j ++){
if(j) printf(" ");
printf("%d",vct[i][j]);
}
printf("\n");
}
}
}
}
return 0;
}