CodeForces 164D Minimum Diameter

洛谷传送门

CF 传送门

先二分答案 \(x\),然后建一张图,距离 \(> x\) 的连边,问题转化为判定这张图的最小点覆盖大小 \(\le k\)

观察到 \(k\) 很小,可以考虑指数级做法。考虑直接搜索,每次把度数最大的点拿出来,枚举它选不选。但是这样最坏复杂度是 \(O(2^k n)\) 的。

发现最大度数 \(\le 2\) 的情况图就是一些环和一些链。对于一个环和链可以直接算出它的最小点覆盖,所以这种情况不用继续搜。

于是每一层搜索可能选 \(1\) 和点或选 \(\ge 3\) 个点。判定的复杂度就是 \(T(k) = T(k - 1) + T(k - 3) + O(n)\)。外面还有一个二分,但是可过。

另一道爆搜求最小点覆盖的题是 P9257 [PA 2022] Mędrcy

code
// Problem: D. Minimum Diameter
// Contest: Codeforces - VK Cup 2012 Round 3
// URL: https://codeforces.com/problemset/problem/164/D
// Memory Limit: 256 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 1010;

ll n, m, a[maxn], b[maxn];
int deg[maxn], stk[maxn], top;
bool e[maxn][maxn], mk[maxn], vis[maxn];
vector<int> G[maxn];

void dfs2(int u) {
	mk[u] = 0;
	stk[++top] = u;
	for (int v : G[u]) {
		if (mk[v]) {
			dfs2(v);
		}
	}
}

bool dfs(vector<int> vc, int d) {
	if (d > m) {
		return 0;
	}
	if (vc.empty()) {
		return 1;
	}
	int p = 0;
	for (int x : vc) {
		if (!p || (deg[x] > deg[p])) {
			p = x;
		}
	}
	if (!deg[p]) {
		return 1;
	}
	if (deg[p] <= 2) {
		for (int x : vc) {
			mk[x] = 1;
		}
		int s = 0;
		for (int x : vc) {
			if (mk[x] && deg[x] == 1) {
				top = 0;
				dfs2(x);
				s += top / 2;
				for (int i = 1 + (top & 1); i < top; i += 2) {
					vis[stk[i]] = 1;
				}
			}
		}
		for (int x : vc) {
			if (mk[x] && deg[x] == 2) {
				top = 0;
				dfs2(x);
				s += (top + 1) / 2;
				for (int i = 1; i <= top; i += 2) {
					vis[stk[i]] = 1;
				}
			}
		}
		if (s + d <= m) {
			return 1;
		} else {
			for (int x : vc) {
				vis[x] = 0;
			}
			return 0;
		}
	}
	vis[p] = 1;
	vector<int> nv;
	for (int x : vc) {
		if (x != p) {
			deg[x] -= e[p][x];
			nv.pb(x);
		}
	}
	if (dfs(nv, d + 1)) {
		return 1;
	}
	vis[p] = 0;
	for (int x : vc) {
		if (x != p) {
			deg[x] += e[p][x];
		}
	}
	vector<int>().swap(nv);
	for (int x : vc) {
		mk[x] = 1;
	}
	for (int x : vc) {
		if (x == p) {
			continue;
		}
		if (e[p][x]) {
			vis[x] = 1;
			for (int y : G[x]) {
				deg[y] -= (y != p && mk[y]);
			}
		} else {
			nv.pb(x);
		}
	}
	for (int x : vc) {
		mk[x] = 0;
	}
	if (dfs(nv, d + deg[p])) {
		return 1;
	}
	for (int x : vc) {
		mk[x] = 1;
	}
	for (int x : vc) {
		if (x == p) {
			continue;
		}
		if (e[p][x]) {
			vis[x] = 0;
			for (int y : G[x]) {
				deg[y] += (y != p && mk[y]);
			}
		} else {
			nv.pb(x);
		}
	}
	for (int x : vc) {
		mk[x] = 0;
	}
	return 0;
}

inline bool check(ll x) {
	mems(e, 0);
	mems(deg, 0);
	mems(mk, 0);
	mems(vis, 0);
	for (int i = 1; i <= n; ++i) {
		vector<int>().swap(G[i]);
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = i + 1; j <= n; ++j) {
			if ((a[i] - a[j]) * (a[i] - a[j]) + (b[i] - b[j]) * (b[i] - b[j]) > x) {
				e[i][j] = e[j][i] = 1;
				G[i].pb(j);
				G[j].pb(i);
				++deg[i];
				++deg[j];
			}
		}
	}
	vector<int> vc;
	for (int i = 1; i <= n; ++i) {
		vc.pb(i);
	}
	return dfs(vc, 0);
}

void solve() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld%lld", &a[i], &b[i]);
	}
	ll l = 0, r = 3e9, ans = -1;
	while (l <= r) {
		ll mid = (l + r) >> 1;
		if (check(mid)) {
			ans = mid;
			r = mid - 1;
		} else {
			l = mid + 1;
		}
	}
	check(ans);
	for (int i = 1; i <= n; ++i) {
		if (vis[i]) {
			printf("%d ", i);
			--m;
		}
	}
	for (int i = 1; i <= n && m; ++i) {
		if (!vis[i]) {
			printf("%d ", i);
			--m;
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-09-20 07:44  zltzlt  阅读(5)  评论(0编辑  收藏  举报