9E - Interestring graph and Apples

原题链接https://codeforces.com/problemset/problem/9/E

题目本身不难,并查集就行,比较容易想到,但是很多细节,找到满足的点之后记得break!再往后找,最小字典序就保证不了了。

题意:
给出了一个图,有n个点,m条边。然后问该图形是否能添加尽量少的边使之成为一个环。输出yes或者no,如果是yes,同时按字典序输出最少添加的边。

思路:构成单独的环,环上的所有点度数都是2,如果有点度数大于2,要么该环没有包括所有点(环上有点分叉连接了其它点),要么该环不是单独的环。
然后我们就可以愉快地用并查集来连边了,只要不在同一个集合里,就可以连边,字典序要求最小,那从小到大遍历就行了。

代码如下

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set> 
#include<iomanip>
#define IOS 	cin.tie(0), ios::sync_with_stdio(false) 
#define x first
#define y second

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int N = 55, M = 10010, mod = 1e9;
const double eps = 1e-4;
const double pi = acos(-1);
const int P = 131;

int d[N], p[N], s[N];
int n, m;
vector<pii> res;

int find(int x)
{
	if(x != p[x])
		p[x] = find(p[x]);
	return p[x];
}

int main()
{
	IOS;
	cin >> n >> m;
	for(int i = 1 ; i <= n ; i ++) p[i] = i, s[i] = 1;
	bool flag = true;
	while(m --)
	{
		int a, b;
		cin >> a >> b;
		int pa = find(a), pb = find(b);
		d[a] ++, d[b] ++;
		if(d[a] > 2 || d[b] > 2) flag = false;
		if(pa != pb)
		{
			s[pb] += s[pa];
			p[pa] = pb;
		}
		else if(s[pa] < n) flag = false;
	}
	
	if(!flag)
	{
		cout << "NO";
		return 0;
	}
	
	while(1)
	{
		int a = 0, b = 0, pa, pb;
		for(int i = 1 ; i <= n ; i ++) 
			if(d[i] < 2)
			{
				a = i;
				break;
			}
		pa = find(a);
		for(int i = 1 ; i <= n ; i ++) 
			if(d[i] < 2 && (pb = find(i)) != pa)
			{
				 b = i;
				 break;
			}
		if(!b) break;
		d[a] ++, d[b] ++;
		p[pa] = pb;
		res.push_back({a, b});
	}
	cout << "YES" << endl;
	int a = 0, b = 0;
	for(int i = 1 ; i <= n ; i ++)
		if(d[i] < 2)
		{
			a = i;
			break;
		}
	for(int i = n ; i ; i --)
		if(d[i] < 2)
		{
			b = i;
			break;
		}
	if(a && b) res.push_back({a, b});
	cout << res.size() << endl;
	for(auto x : res) cout << x.x << " " << x.y << endl;
	return 0;
}
上一篇:MATLAB实现灰度图像的直方图均衡化算法


下一篇:指针进阶