洛谷传送门
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;
}