题意:
给出n个城市的坐标,要在城市中建设k个飞机场,使城市距离最近的飞机场的最长距离最小,求这个最小距离。
分析:
计算最大距离的最小值,很显然二分查找距离,再借助Dancing Links进行覆盖,看是否在k个城市内覆盖完所有的城市。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int maxm=1005;
const int maxnode=maxn*maxm;
const int inf=0x3f3f3f3f;
int n,k;
struct DLX{
int n,m,size;
int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
int H[maxn],S[maxm];
int ansd,ans[maxn];
void init(int _n,int _m){
n=_n;
m=_m;
for(int i=0;i<=m;i++){
S[i]=0;
U[i]=D[i]=i;
L[i]=i-1;
R[i]=i+1;
}
R[m]=0;L[0]=m;
size=m;
for(int i=1;i<=n;i++){
H[i]=-1;
}
}
void Link(int r,int c){
++S[Col[++size]=c];
Row[size]=r;
D[size]=D[c];
U[D[c]]=size;
U[size]=c;
D[c]=size;
if(H[r]<0) H[r]=L[size]=R[size]=size;
else{
R[size]=R[H[r]];
L[R[H[r]]]=size;
L[size]=H[r];
R[H[r]]=size;
}
}
void remove(int c){
for(int i=D[c];i!=c;i=D[i]){
L[R[i]]=L[i];
R[L[i]]=R[i];
}
}
void resume(int c){
for(int i=U[c];i!=c;i=U[i]){
L[R[i]]=R[L[i]]=i;
}
}
bool v[maxm];
int f(){
int ret=0;
for(int c=R[0];c!=0;c=R[c]) v[c]=1;
for(int c=R[0];c!=0;c=R[c]){
if(v[c]){
ret++;
v[c]=false;
for(int i=D[c];i!=c;i=D[i]){
for(int j=R[i];j!=i;j=R[j]){
v[Col[j]]=false;
}
}
}
}
return ret;
}
bool dance(int d){
if(d+f()>k) return false;
if(R[0]==0){
return d<=k;
}
int c=R[0];
for(int i=R[0];i!=0;i=R[i]){
if(S[i]<S[c]){
c=i;
}
}
for(int i=D[c];i!=c;i=D[i]){
remove(i);
for(int j=R[i];j!=i;j=R[j]) remove(j);
if(dance(d+1)) return true;
for(int j=L[i];j!=i;j=L[j]) resume(j);
resume(i);
}
return false;
}
}dlx;
typedef long long ll;
struct node{
ll x,y;
}p[100];
ll dis[100][100];
ll dist[100*100];
inline ll distance(int i,int j){
return abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y);
}
bool judge(ll mid){
dlx.init(n,n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(dis[i][j]<=mid){
dlx.Link(i+1,j+1);
}
}
}
return dlx.dance(0);
}
int main(){
int T;
scanf("%d",&T);
for(int cs=1;cs<=T;cs++){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%lld%lld",&p[i].x,&p[i].y);
}
int cnt=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
dis[i][j]=distance(i,j);
dist[cnt++]=dis[i][j];
}
}
sort(dist,dist+cnt);
cnt=unique(dist,dist+cnt)-dist;
int l=-1,r=cnt;
while(r-l>1){
int mid=l+r>>1;
if(judge(dist[mid])) r=mid;
else l=mid;
}
printf("Case #%d: %lld\n",cs,dist[r]);
}
return 0;
}