题目链接:点我啊╭(╯^╰)╮
题目大意:
给定 n n n 个城市的坐标,要在这 n n n 个城市里建 k k k 个飞机场,要使任意城市离最近的飞机场距离的最大值最小
解题思路:
最大值最小化,很典型的二分,即二分城市与飞机场的距离,若满足
k
k
k 个以内的飞机场在这个距离内能覆盖所有城市,则减小这个二分值
那么我们就解决了怎么得到这个最小值,但问题的关键是怎么去判断k个飞机场能否覆盖所有城市,这里的思路几乎与HDU 2295是同一个套路
我们用二分的距离去判断可行性,若在两座城市的距离在这个距离内,那么就在DLX模型中建边,则转化为了可重复覆盖的问题
代码思路:
如果直接套模板的话不知道能不能过,在本题内有两个除模板以外的两个优化:
①:因为我们要判断的是能否在
k
k
k 行内覆盖完,所以在 dfs 的过程中对深度与k进行比较,加速返回
②:在本题中直接对距离的最大值进行二分是不足够好的,看了别人的题解之后发现可以对所有的距离值进行二分,思路是:先把所有城市的距离用数组存下来,排序+去重,然后直接二分数组下标即可,极大的优化了时间复杂度
核心:二分 + DLX 的好题,对优化要做到位
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,k,cas,t=1;
pair <ll,ll> city[65];
ll dis[65][65], val[3650];
struct DancingLink{
const static int N = 500010;
const static int M = 1010;
int n, s, ansd; // 列数 节点总数
int S[M], A[M], H[M]; // S[]该列节点总数 A[]答案 H[]行首指针
int L[N], R[N], U[N], D[N]; // L[],R[],U[],D[] 上下左右
int X[N], C[N], vis[M]; // X[] C[] 行列编号
void init(int n){ // 初始化
this->n = n;
for(int i=0; i<=n; i++)
U[i]=i, D[i]=i, L[i]=i-1, R[i]=i+1;
R[n]=0, L[0]=n; s=n+1;
memset(S, 0, sizeof(S));
memset(H, -1, sizeof(H));
}
void DelCol(int c){ // 删除列
for(int i=D[c]; i!=c; i=D[i])
L[R[i]]=L[i], R[L[i]]=R[i];
}
void ResCol(int c){ // 恢复列
for(int i=U[c]; i!=c; i=U[i])
L[R[i]]=R[L[i]]=i;
}
void AddNode(int r,int c){ // 添加节点
++S[c], C[++s]=c, X[s]=r;
D[s]=D[c], U[D[c]]=s, U[s]=c, D[c]=s;
if(H[r]<0) H[r]=L[s]=R[s]=s; // 行首节点
else R[s]=R[H[r]], L[R[H[r]]]=s, L[s]=H[r], R[H[r]]=s;
}
int f(){
int ret=0;
memset(vis, 0, sizeof(vis));
for(int i=R[0]; i; i=R[i])
if(!vis[i]){
ret++; vis[i]=1;
for(int j=D[i]; j!=i; j=D[j])
for(int k=R[j]; k!=j; k=R[k])
vis[C[k]]=1;
}
return ret;
}
bool dfs(int d){ // 深度,深搜遍历
if(d+f() > k) return 0;
if(!R[0]) return d <= k;
int c=R[0];
for(int i=R[0]; i; i=R[i]) if(S[i]<S[c]) c=i;
for(int i=D[c]; i!=c; i=D[i]){
DelCol(i); A[d]=X[i];
for(int j=R[i]; j!=i; j=R[j]) DelCol(j);
if(dfs(d+1)) return 1;
for(int j=L[i]; j!=i; j=L[j]) ResCol(j);
ResCol(i);
}
return 0;
}
} dlx;
bool check(ll w) {
dlx.init(n);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(dis[i][j]<=w)
dlx.AddNode(i,j);
return dlx.dfs(0);
}
int main() {
scanf("%d", &cas);
while(cas--) {
scanf("%d%d", &n, &k);
int cnt = 0;
for(int i=1; i<=n; i++) {
scanf("%lld%lld", &city[i].first, &city[i].second);
for(int j=1; j<=i; j++) {
dis[i][j]=dis[j][i]=val[cnt++]=\
fabs(city[i].first-city[j].first)+\
fabs(city[i].second-city[j].second);
}
}
sort(val, val+cnt);
cnt = unique(val, val + cnt) - val;
int l = 0, r = cnt-1, mid;
while(l<=r) {
mid = (l+r)/2;
if(check(val[mid])) r = mid - 1;
else l = mid + 1;
}
printf("Case #%d: %lld\n", t++, val[r+1]);
}
}