給定 n 個機場坐標,需選出 K 個作為樞紐,使得每個機場到最近樞紐的曼哈頓距離最大值最小。n ≤ 60, K ≤ n。
[0, 2e11](坐標絕對值 ≤ 1e9)。struct DLX {
static const int MAXNODE = 4005; // n=60, n^2=3600 節點上限
static const int MAXM = 65, MAXN = 65;
int U[MAXNODE], D[MAXNODE], L[MAXNODE], R[MAXNODE];
int row[MAXNODE], col[MAXNODE];
int H[MAXN], S[MAXM]; // 行頭指針、列大小
int ansd, ans[MAXN]; // 當前解深度、解記錄
bool v[MAXNODE]; // 估價函數用訪問標記
void init(int n, int m) { /* 初始化列頭雙向鏈表 */ }
void Link(int r, int c) { /* 插入節點到第 r 行第 c 列 */ }
void remove(int c), resume(int c); // 列刪除/恢復
int f() { /* 估價:貪心計算覆蓋剩餘列所需最少行數 */ }
bool Dance(int d) { /* 深度優先搜索,剪枝:d + f() > K */ }
};
S[c] 最小的列展開(最少選擇分支)。f():貪心選擇覆蓋最多未覆蓋列的行,計算下界。若 d + f() > K 剪枝。#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 65;
struct City { ll x, y; void read() { scanf("%lld%lld", &x, &y); } } c[N];
ll dist(City a, City b) { return llabs(a.x-b.x) + llabs(a.y-b.y); }
int main() {
int T; scanf("%d", &T);
for (int cas = 1; cas <= T; ++cas) {
int n, K; scanf("%d%d", &n, &K);
for (int i = 1; i <= n; ++i) c[i].read();
ll L = 0, R = 100000000000LL;
while (L < R) {
ll mid = (L + R) >> 1;
DLX solver; solver.init(n, n);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (dist(c[i], c[j]) <= mid) solver.Link(i, j);
if (solver.Dance(0)) R = mid;
else L = mid + 1;
}
printf("Case #%d: %lld\n", cas, L);
}
return 0;
}
llabs 防溢位。