思路
从n城市中选择k个来修建机场,使所有城市到达机场的距离最大值最小
既然是求“距离的最大值最小”,那么就要用二分在枚举去枚举 这个最大值最小的距离md,之后在写一个判读函数 check(),进行二分的区间选择 对于check函数,当我们枚举了一个距离md之后,问题就转化为,能否存在一中方案从n个中选择k个城市使所有的城市都被覆盖,现在怎么选择k个合适的城市的问题? 我们参考:DLX问题中的精确覆盖问题:从n行中选择一些行,使这些行组成的集合的中的每一列都只有一个1(只能被覆盖一次) 在我们这个题中:我们可以让:n个城市作为行来进行选择,在让n个城市作为列,作为 被覆盖的对象,所以可以构造出一个 n * n 的数据矩形,对于这个数据矩形的行,某一行所代表的城市(设为i),在距离md之下能够覆盖某一例的城市(设为j),那么在 数据矩形中 (i,j)位置的数字就为1,否则的哈就为0,这样就构造好了 数据矩形 但是如果用 “DLX中的精确覆盖”
(不能有重复覆盖的情况),我们发现每个城市可以被多个城市被多个机场覆盖——这个意味着我们选择的k中形成的集合的每一列可以有多个1(在每一列都有1的情况下), 所以我们要用 “DLX中的重复覆盖”
(运行每行有多个1,也就是 被覆盖的对象可以被覆盖多次) 重复覆盖的代码与 精确覆盖的代码 有稍微的不同,主要体现在我们选择某一个之后,进行的删除操作
对于精确覆盖:我在选择某一行之后,将这一行的存在的列全部删除(这些列已经被覆我们选所择行的1的盖过了),之后再降我们删除的所有列上存在元素的对应的行也删去(这些列已经被我们选的的行的1覆盖过了,“其它行”在这些列里面存在的1,所以“其它行”全部不可以在使用了) 对于重复覆盖:我们在选择某一行之后,将这一行删除,之后在将在这一行上存在1的列删除---------------------之后相交于 “精确覆盖问题”就没了,因为我们选择的当前行的1覆盖列之后,“其它行”的1任然可以覆盖已经被覆盖过的列的,所以“其它行”就不用被删除了,可以在后面继续被使用 重复覆盖因为删除 行 少了,所以递归的层数会变多,所以加了一个剪枝行h(),它返回一个数,这个数表示从当前覆盖情况下,最少还需要几次覆盖才使所有的列都被1覆盖
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
#include <string>
#include <cstdio>
#include <cmath>
#include <stack>
void fre ( ) { system ( "clear" ) , freopen ( "A.txt" , "r" , stdin ) ; freopen ( "Ans.txt" , "w" , stdout ) ; }
void Fre ( ) { system ( "clear" ) , freopen ( "A.txt" , "r" , stdin ) ; }
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define m_p make_pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(int i = (ll)(e); i >= (ll)(s); i --)
#define sd(a) scanf("%d", &a)
#define sc(a) scanf("%c", &a)
using namespace std;
const int mxnode = 1e4 ;
const int mxn = 100 ;
pair< ll, ll> city[ mxn] ;
ll dis[ mxn] [ mxn] ;
ll val[ mxnode] ;
int n, k;
struct DLX
{
int U[ mxnode] , D[ mxnode] , R[ mxnode] , L[ mxnode] ;
int Col[ mxnode] , Row[ mxnode] ;
int H[ mxnode] , S[ mxnode] ;
int ans, ansd[ mxn] ;
int size, n;
int vis[ mxn] ;
void init ( int _n)
{
n = _n;
for_ ( i, 0 , n)
{
L[ i] = i - 1 ;
R[ i] = i + 1 ;
U[ i] = D[ i] = i;
}
R[ n] = 0 , L[ 0 ] = n, size = n;
memset ( H, - 1 , sizeof ( H) ) ;
memset ( S, 0 , sizeof ( S) ) ;
}
void link ( int r, int c)
{
Col[ ++ size] = c;
Row[ size] = r;
S[ c] ++ ;
U[ size] = U[ c] ;
D[ size] = c;
D[ U[ c] ] = size;
U[ c] = size;
if ( H[ r] == - 1 )
H[ r] = L[ size] = R[ size] = size;
else
{
L[ size] = size - 1 ;
R[ size] = H[ r] ;
R[ L[ size] ] = size;
L[ 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] ] = i, R[ L[ i] ] = i;
}
int h ( )
{
memset ( vis, 0 , sizeof ( vis) ) ;
int sum = 0 ;
for ( int i = R[ 0 ] ; i; i = R[ i] )
{
if ( vis[ i] ) continue ;
vis[ i] = 1 ;
sum ++ ;
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 sum;
}
bool dance ( int d)
{
if ( d + h ( ) > k) return false;
if ( R[ 0 ] == 0 ) return d <= k;
int c = R[ 0 ] ;
for ( int i = R[ 0 ] ; i; i = R[ i] )
if ( S[ c] > S[ i] )
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;
ll Dis ( int i, int j)
{
return abs ( city[ i] . fi - city[ j] . fi) + \
abs ( city[ i] . se - city[ j] . se) ;
}
bool check ( ll w)
{
dlx. init ( n) ;
for_ ( i, 1 , n)
for_ ( j, 1 , n)
if ( dis[ i] [ j] <= w)
dlx. link ( i, j) ;
return dlx. dance ( 0 ) ;
}
int main ( )
{
int T, Case = 1 ;
sd ( T) ;
while ( T -- )
{
scanf ( "%d %d" , & n, & k) ;
int cnt = 0 ;
for_ ( i, 1 , n)
{
scanf ( "%lld %lld" , & city[ i] . fi, & city[ i] . se) ;
for_ ( j, 1 , i)
dis[ i] [ j] = dis[ j] [ i] = val[ cnt ++ ] = Dis ( i, j) ;
}
sort ( val, val + cnt) ;
cnt = unique ( val, val + cnt) - val;
int l = 0 , r = cnt - 1 ;
while ( l < r)
{
int md = l + r >> 1 ;
if ( check ( val[ md] ) )
r = md;
else
l = md + 1 ;
}
printf ( "Case #%d: %lld\n" , Case ++ , val[ r] ) ;
}
return 0 ;
}