The country of jiuye composed by N cites. Each city can be viewed as a point in a two- dimensional plane with integer coordinates (x,y). The distance between city i and city j is defined by d ij = |x i - x j| + |y i - y j|. jiuye want to setup airport in K cities among N cities. So he need your help to choose these K cities, to minimize the maximum distance to the nearest airport of each city. That is , if we define d i(1 ≤ i ≤ N ) as the distance from city i to the nearest city with airport. Your aim is to minimize the value max{d i|1 ≤ i ≤ N }. You just output the minimum.
Input
The first line of the input is T (1 ≤ T ≤ 100), which stands for the number of test cases you need to solve.
The first line of each case contains two integers N ,K (1 ≤ N ≤ 60,1 ≤ K ≤ N ),as mentioned above.
The next N lines, each lines contains two integer x i and y i (-10 9 ≤ x i, y i ≤ 10 9), denote the coordinates of city i.
Output
For each test case, print a line “Case #t: ”(without quotes, t means the index of the test case) at the beginning. Then a single integer means the minimum.
Sample Input
2
3 2
0 0
4 0
5 1
4 2
0 3
1 0
3 0
8 9
Sample Output
Case #1: 2
Case #2: 4
妈的,这道题是Radar的变形题,一直不知道怎么构造矩阵,看到二分长度,突然明白,二分最大长度,那么就增加了一个约束条件,那么矩阵的列就好构建了,01矩阵行是城市,列也是城市,只有曼哈顿距离小于当前二分的最大长度,矩阵才能标1
注意:被数据范围坑到了,4*1e9超int了,应该用long long
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const double eps = 1e-8;
//最大行数
const int MN = 1005;
//最大列数
const int MM = 1005;
//最大点数
const int MNN = 1e5 + 5 + MM;
struct DLX
{
//一共n行m列,s个节点
int n,m,s;
//交叉十字链表组成部分
//第i个节点的上U下D左L右R,所在位置row行col列
int U[MNN],D[MNN],L[MNN],R[MNN],row[MNN],col[MNN];
//H数组记录行选择指针,S数组记录覆盖个数
int H[MN],S[MM];
//res记录行个数,ans数组记录可行解
int res,ans[MN];
//初始化空表
void init(int x,int y)
{
n = x,m = y;
//其中0节点作为head节点,其他作为列首节点
for(int i = 0;i <= m;++i){
U[i] = D[i] = i;
L[i] = i - 1;
R[i] = i + 1;
}
R[m] = 0;L[0] = m;
s = m;
memset(S,0,sizeof(S));
memset(H,-1,sizeof(H));
}
void Insert(int r,int c)
{
//节点数加一,设置s节点所处位置,以及S列覆盖个数加一
s++;row[s] = r;col[s] = c;S[c]++;
//将s节点插入对应列中
D[s] = D[c];U[D[c]] = s;
U[s] = c;D[c] = s;
if(H[r] < 0){//如果该行没有元素,H[r]标记该行起始节点
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;
}
}
//精确覆盖
void Remove(int c)
{
//删除c列
L[R[c]] = L[c];R[L[c]] = R[c];
//删除该列上的元素对应的行
for(int i = D[c];i != c;i = D[i]){//枚举该列元素
for(int j = R[i];j != i;j = R[j]){//枚举列的某个元素所在行遍历
U[D[j]] = U[j];
D[U[j]] = D[j];
//将该列上的S数组减一
--S[col[j]];
}
}
}
void resume(int c)
{
//恢复c列
for(int i = U[c];i != c;i = U[i]){//枚举该列元素
for(int j = L[i];j != i;j = L[j]){
U[D[j]] = j;D[U[j]] = j;
++S[col[j]];
}
}
L[R[c]] = c;R[L[c]] = c;
}
bool dance(int deep)
{
if(res < deep) return false;
//当矩阵为空时,说明找到一个可行解,算法终止
if(R[0] == 0){
res = min(res,deep);
return true;
}
//找到节点数最少的列,枚举这列上的所有行
int c = R[0];
for(int i = R[0];i != 0;i = R[i]){
if(S[i] < S[c]){
c = i;
}
}
//删除节点数最少的列
Remove(c);
for(int i = D[c];i != c;i = D[i]){
//将行r放入当前解
ans[deep] = row[i];
//行上节点对应的列上进行删除
for(int j = R[i];j != i;j = R[j])
Remove(col[j]);
//进入下一层
dance(deep + 1);
//对行上的节点对应的列进行恢复
for(int j = L[i];j != i;j = L[j])
resume(col[j]);
}
//恢复节点数最少列
resume(c);
return false;
}
//重复覆盖
//将列与矩阵完全分开
void Remove1(int c)
{
for(int i = D[c];i != c;i = D[i]){
L[R[i]] = L[i];
R[L[i]] = R[i];
}
}
void resume1(int c)
{
for(int i = D[c];i != c;i = D[i]){
L[R[i]] = R[L[i]] = i;
}
}
int vis[MNN];
//估价函数,模拟删除列,H(),函数返回的是至少还需要多少行才能完成重复覆盖
int A()
{
int dis = 0;
for(int i = R[0];i != 0;i = R[i]) vis[i] = 0;
for(int i = R[0];i != 0;i = R[i]){
if(!vis[i]){
dis++;vis[i] = 1;
for(int j = D[i];j != i;j = D[j]){
for(int k = R[j];k != j;k = R[k]){
vis[col[k]] = 1;
}
}
}
}
return dis;
}
bool dfs(int deep)
{
if(deep + A() > res) return false;
if(!R[0]) return true;
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]){
//每次将第i列其他节点删除,只保留第i节点,为了找该行的节点
Remove1(i);
//将列上的节点完全与矩阵脱离,只删列首节点是不行的
for(int j = R[i];j != i;j = R[j]){
Remove1(j);
}
if(dfs(deep + 1)) return true;
for(int j = L[i];j != i;j = L[j]){
resume1(j);
}
resume1(i);
}
return false;
}
int IDEA(int k)
{
res = 0;
while(true)
{
if(res > k) break;
//cout << res << endl;
if(dfs(0)) return res;
res++;
}
return -1;
}
}dlx;
const LL MAX = 4 * 1e9;
//01矩阵的行是城市,列是城市
typedef struct Node{
LL x,y;
}Node;
Node a[65];
LL dis(int i,int j)
{
return abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y);
}
int n,k;
bool change(LL len)
{
dlx.init(n,n);
for(int i = 1;i <= n;++i){
for(int j = 1;j <= n;++j){
if(dis(i,j) <= len){
dlx.Insert(i,j);
}
}
}
int num = dlx.IDEA(k);
//cout << num << endl;
if(num > k || num == -1){
return false;
}else{
return true;
}
}
int main()
{
//printf("%d\n",MAX);
int t;
scanf("%d",&t);
int cnt = 0;
while(t--)
{
cnt++;
scanf("%d %d",&n,&k);
for(int i = 1;i <= n;++i){
scanf("%lld %lld",&a[i].x,&a[i].y);
}
LL l = 0,r = MAX;
while(l <= r){
LL mid = (l + r) / 2;
//cout << mid << endl;
if(change(mid)) r = mid - 1;
else l = mid + 1;
}
printf("Case #%d: %lld\n",cnt,l);
}
return 0;
}