【贪心】P7403 [BalticOI 2002 Day1] Tennis Club

目前题解区还没有证明,我交个证明。

形式化题意

给定每个点的度数 di,请构造一个简单无向图(无重边无自环)。

First. 无解

首先,根据握手定理,每个无向图的度数之和为边数的两倍,所以如果度数之和为奇数,那么肯定无解。

但是发现,这种情况之外还有别的无解情况(本题有 3 个无解数据,只能 AC 一个)。

而这种情况,就需要给出一个保证正确的构造方案,如果无法构造那么无解。

Second. 构造

这里介绍一个定理:

Havel-Hakimi定理

一个不降序度数序列 d={d1,d2,,dn} 若其可以简单图化,当且仅当 d={d21,d31,,dd1+11,dd1+2,,dn} 可以简单图化。

  1. 证明:d 若其可以简单图化,那么 d 可以简单图化。

    两种情况:

    1. G 中存在边 {(1,2),(1,3),,(1,d1+1)},显然,此时删去这些边该图仍然为简单图且满足度数序列 d,所以 d 可简单图化。
    2. G 中存在点对 (i,j) 满足 didj 且仅存在边 (1,j) 而不存在边 (1,i)id1+1,j>d1+1,那么此时由于 didj 那么一定存在一个点 u 满足存在 (i,u) 但不存在 (j,u),将 (i,u) 修改为 (1,u)(1,j) 修改为 (j,u),该图度数序列不变且仍然为简单图,此时,情况又变为情况 1
  2. 证明:d 可以简单图化,那么 d 可以简单图化。
    构造很简单,12,3,,d1+1 连边,该图仍为简单图,且度数序列变为 d

显然,度数序列 d={0,0,,0} 一定可以简单图化,那么只需要重复运用定理,直至度数序列化为 d={0,0,,0} 即可。

如果不能进行如上操作(即 di1<0(2id1+1)),那么无解。

注意,定理中的 d不降序度数序列,那么每次操作后需要排序才能再次进行操作。

Code

#include <bits/stdc++.h>
using namespace std;

const int N = 1e3 + 10;
int n;
pair<int, int> g[N];
vector<int> ans[N];

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n;
	int d = 0;
	for (int i = 1; i <= n; i ++) {
		cin >> g[i].first;
		g[i].second = i, d += g[i].first;
	}
	if (d & 1) { // 握手定理
		cout << "NO SOLUTION\n";
		return 0;
	}
	for (int t = 1; t <= n; t ++) {
		sort(g + 1, g + 1 + n); // 排序
		int j = n - 1;
		while (g[n].first) { // 从次大值开始减
			g[j].first --, g[n].first --;
			if(g[j].first < 0) { //无法加边,无解
				cout << "NO SOLUTION\n";
				return 0;
			}
			ans[g[j].second].push_back(g[n].second);
			ans[g[n].second].push_back(g[j].second);
			j --;
		}
	}
	cout << "SOLUTION\n";
	for (int i = 1; i <= n; i ++) {
		for (auto u : ans[i]) cout << u <<  ' ';
		cout << endl;
	}
	return 0;
}
posted @   固态H2O  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示