题目链接:https://codeforces.com/contest/9/problem/E
题目大意
给你一个图,判断是否可以将所有点都连成一条环,所有点都只在这一个环中,最后输出需要加边的最小边数,且输出字典序最小的增加的边序列
题解
首先,一开始无解的情况就是如果有一个点的度数大于2,那么肯定不止最后那一个环,所以是无解的。
如果有解,图应该含有许多连通块,用并查集维护这些连通块,可以按下面的步骤得到答案
1.从小到大暴力地连接所有不在同一个连通块内的节点,这里用并查集维护相当方便
2.连接完成,最后所有的点都应该在同一个并查集内,再将并查集的首位相连
3.最后判断是否存在只有一个点的情况,这种情况还要连接自环
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 50 + 10;
int n, m;
int in[maxn];
vector<int>G[maxn];
int fa[maxn];
struct Edge {
int u, v;
Edge(int i,int j):u(i),v(j){}
};
int cmp(const Edge a, const Edge b) {
return a.u < b.u || (a.u == b.u && a.v < b.v);
}
vector<Edge>ans;
int find_set(int x) {
return fa[x] == x ? fa[x] : fa[x] = find_set(fa[x]);
}
void Union(int x, int y) {
int fx = find_set(x);
int fy = find_set(y);
if (fx != fy) {
if (fx < fy) {
fa[fy] = fx;
}
else {
fa[fx] = fy;
}
}
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
memset(in, 0, sizeof(in));
for (int i = 1; i <= n; i++)fa[i] = i;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
Union(u, v);
in[v]++;
in[u]++;
}
bool flag = true;
for (int i = 1; i <= n; i++) {
if (in[i] >= 3) {
flag = false;
break;
}
}
if (!flag) {
cout << "NO" << endl;
return 0;
}
//从小到大枚举不同联通分量的点的连边
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (find_set(i) != find_set(j) && in[i] != 2 && in[j] != 2) {
ans.push_back(Edge( j, i ));
Union(i,j);
in[i]++, in[j]++;
}
}
}
//同一个联通分量,首尾相连
for (int i = 1; i <= n; i++) {
if (in[i] == 2)continue;
for (int j = 1; j < i; j++)
{
if (in[j] == 1)
{
ans.push_back(Edge(j, i));
Union(i, j);
in[i]++;
in[j]++;
}
}
}
//一个点就是自环
//一个点必须连他自己,数据会卡掉不连自己的情况
for (int i = 1; i <= n; i++)
{
if (in[i] == 0) {
ans.push_back(Edge(i, i));
}
}
int root = find_set(1);
for (int i = 1; i <= n; i++) {
if (find_set(i) != root) {
cout << "NO" << endl;
return 0;
}
}
cout << "YES" << endl;
sort(ans.begin(), ans.end(), cmp);
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); i++) {
cout << ans[i].u << " " << ans[i].v << endl;
}
return 0;
}