【HDU】5046 Airport 二分+重复覆盖

传送门:【HDU】5046 Airport


题目分析:DLX的模板题。。。二分最长长度,然后建边跑DLX,如果选择不超过K的方案存在则调整上界,否则调整下界。就这么简单,当然可以用rabbit巨巨告诉我的一个方法优化二分次数:直接找到所有的距离对,离散后将距离对按照升序排列在数组里,然后二分的时候直接二分数组下标即可,因为最多只有1800项,比直接二分距离复杂度小了太多太多。。


今天我实在是傻逼。。。以为不写高度函数没有关系。。。结果最后就因为这个TLE了。。更傻逼的是TLE了后还没想去加高度函数。。。T U T。。赛后加了就AC了,怎么会有我这么2的人呢。。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
//using namespace std ;

typedef long long LL ;

#pragma comment(linker, "/STACK:16777216")
#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define rec( i , A , o ) for ( int i = A[o] ; i != o ; i = A[i] )
#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define mid ( ( l + r ) >> 1 )
#define root 1 , 1 , n

const int MAXNODE = 10000 ;
const int MAXN = 100 ;
const int MAXR = 100 ;
const int MAXC = 100 ;

struct Point {
	int x , y ;
} p[MAXN] ;

int U[MAXNODE] , D[MAXNODE] , L[MAXNODE] , R[MAXNODE] ;
int H[MAXR] , S[MAXC] ;
int col[MAXNODE] ;
int size ;
int n , K ;
LL d[MAXN][MAXN] ;
LL a[3000] ;
bool vis[MAXN] ;
int cnt ;

void clear ( int n ) {
	For ( i , 0 , n ) {
		L[i] = i - 1 ;
		R[i] = i + 1 ;
		U[i] = D[i] = i ;
		S[i] = 0 ;
	}
	clr ( H , -1 ) ;
	L[0] = n ;
	R[n] = 0 ;
	size = n ;
}

void link ( int r , int c ) {
	++ size ;
	S[c] ++ ;
	col[size] = c ;
	U[size] = U[c] ;
	D[size] = c ;
	D[U[c]] = size ;
	U[c] = size ;
	if ( H[r] != -1 ) {
		L[size] = L[H[r]] ;
		R[size] = H[r] ;
		L[R[size]] = size ;
		R[L[size]] = size ;
	} else H[r] = L[size] = R[size] = size ;
}

void remove ( int c ) {
	rec ( i , D , c ) {
		L[R[i]] = L[i] ;
		R[L[i]] = R[i] ;
	}
}

void resume ( int c ) {
	rec ( i , U , c ) {
		L[R[i]] = R[L[i]] = i ;
	}
}

int h () {
	int cnt = 0 ;
	clr ( vis , 0 ) ;
	rec ( i , R , 0 ) if ( !vis[i] ) {
		++ cnt ;
		vis[i] = 1 ;
		rec ( j , D , i ) rec ( k , R , j ) vis[col[k]] = 1 ;
	}
	return cnt ;
}

int dance ( int d = 0 ) {
	if ( d + h () > K ) return 0 ;
	if ( !R[0] ) return 1 ;
	int c = R[0] ;
	rec ( i , R , 0 ) if ( S[c] > S[i] ) c = i ;
	rec ( i , D , c ) {
		remove ( i ) ;
		rec ( j , R , i ) remove ( j ) ;
		if ( dance ( d + 1 ) ) return 1 ;
		rec ( j , L , i ) resume ( j ) ;
		resume ( i ) ;
	}
	return 0 ;
}

void make_map ( LL dist ) {
	clear ( n ) ;
	rep ( i , 0 , n ) {
		link ( i + 1 , i + 1 ) ;
		rep ( j , i + 1 , n ) {
			if ( d[i][j] <= dist ) {
				link ( i + 1 , j + 1 ) ;
				link ( j + 1 , i + 1 ) ;
			}
		}
	}
}

int unique ( int n ) {
	int cnt = 1 ;
	std :: sort ( a + 1 , a + n + 1 ) ;
	For ( i , 2 , n ) if ( a[cnt] != a[i] ) a[++ cnt] = a[i] ;
	return cnt ;
}

void solve () {
	scanf ( "%d%d" , &n , &K ) ;
	rep ( i , 0 , n ) scanf ( "%d%d" , &p[i].x , &p[i].y ) ;
	cnt = 0 ;
	rep ( i , 0 , n ) rep ( j , i + 1 , n ) d[j][i] = d[i][j] = ( LL ) abs ( p[i].x - p[j].x ) + ( LL ) abs ( p[i].y - p[j].y ) ;
	rep ( i , 0 , n ) rep ( j , i + 1 , n ) a[++ cnt] = d[i][j] ;
	a[++ cnt] = 0 ;
	cnt = unique ( cnt ) ;
	int l = 1 , r = cnt ;
	LL ans = 0 ;
	while ( l < r ) {
		int m = ( l + r ) >> 1 ;
		make_map ( a[m] ) ;
		if ( dance () ) r = m ;
		else l = m + 1 ;
	}
	printf ( "%I64d\n" , a[l] ) ;
}

int main () {
	int T , cas = 0 ;
	scanf ( "%d", &T ) ;
	while ( T -- ) {
		printf ( "Case #%d: " , ++ cas ) ;
		solve () ;
	}
	return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值