题意:给出了一个图,有n个点,m条边。然后问该图形是否能添加尽量少的边使之成为一个环。输出yes或者no,如果是yes,按字典序输出添加的边。
题解:显然,条件的边数是确定的,n个点,总共需要n - 1条边,且一个环上的点,度数为2,所以并查集维护一下,然后枚举点,把度数不足的连线即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 60;
struct node{
int fa[maxn];
void init(){
for (int i = 0; i < maxn; i ++){
fa[i] = i;
}
}
int found(int x) {return fa[x] = fa[x] == x ? x : found(fa[x]);}
bool combine(int x, int y){
int a = found(x), b = found(y);
if(a == b) return false;
else fa[b] = a;
return true;
}
} uf;
int n, m;
int s[maxn];
int main(){
while(scanf("%d %d", &n, &m) != EOF){
bool flag = true;
uf. init();
for (int i = 0; i <= n; i ++)
s[i] = 2;
for (int i = 0; i < m; i ++){
int c,d;
scanf("%d %d", &c, &d);
s[c] --, s[d] --;
if(s[c] < 0 || s[d] < 0)
flag = false;
if(uf. found(c) == uf.found(d) && i != n - 1)
flag = false;
uf. combine(c, d);
}
if(flag){
puts("YES");
printf("%d\n", n - m);
for (int i = 1;i <= n; i ++){
for (int q = 0; q <= 1; q ++){
for (int j = i + 1; j <= n; j ++){
if(s[i] && s[j] && uf. combine(i, j)){
s[i] --, s[j] --;
printf("%d %d\n", i, j);
}
}
}
}
int cnt = 1;
for (int i = 1; i <= n; i ++){
while(s[i] --){
printf("%d", i);
if(cnt) {
printf(" ");
cnt = 0;
}
else {
printf("\n");
cnt = 1;
}
}
}
}
else puts("NO");
}
return 0;
}