CodeForces 164D Minimum Diameter
先二分答案 \(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;
}