HDU 5046 Airport ( Dancing Links 重复覆盖 )

今年上海网络赛的一道题目 , 跟 HDU 2295 如出一辙 , 就是距离的计算一个是欧几里得距离 , 一个是曼哈顿距离

学完DLX感觉这题好水 ,就是一个裸的重复覆盖

注意下别溢出就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <stdlib.h>
using namespace std;    

const int maxn = 60 + 10 ;
const int maxr = 60 + 10 ;
const int maxnode = 60 * 60 + maxr + 10 ;    

#define FOR( i , A , s ) for( int i = A[s] ; i != s ; i = A[i] )     

struct DLX{
	// maxn 列数 , maxnode 总节点数 , maxr 行数
	int n , sz ;
	int S[maxn] ;     

	int row[maxnode] , col[maxnode] ;
	int L[maxnode] , R[maxnode] , U[maxnode] , D[maxnode] ;
	int H[maxr] ;    

	int ansd , ans[maxr] ;    

	void init( int N ) {
		n = N ;
		// 第一行的虚拟结点
		for( int i = 0 ; i <= n ; i ++ ) {
			U[i] = D[i] = i ;
			L[i] = i - 1 ;
			R[i] = i + 1 ;
		}
		R[n] = 0 ; L[0] = n ;
		sz = n + 1 ;
		// 每一列的个数
		memset( S , 0 , sizeof(S) ) ;
		// H[i] = -1 表示这一行还没有 1
		// 否则表示第一个 1 的 sz 是多少
		memset( H , -1 , sizeof(H)) ;
	}    

	// 在第r行第c列添加一个1
	void Link( int r , int c ) {
		row[sz] = r ;
		col[sz] = c ;
		S[c] ++ ;    

		D[sz] = c ; U[sz] = U[c] ;
		D[U[c]] = sz ; U[c] = sz ;    

		if( H[r] < 0 ) { H[r] = L[sz] = R[sz] = sz ; }
		else{
			R[sz] = H[r] ;
			L[sz] = L[H[r]] ;
			R[L[sz]] = sz ;
			L[R[sz]] = sz ;
		}    

		sz ++ ;    

	}    

	// 删除 第 c 列
	void remove ( int c ) {
		FOR( i , D , c ) {
			L[R[i]] = L[i] ;
			R[L[i]] = R[i] ;
		}
	}    

	// 恢复第 c 列
	void restore( int c ) {
		FOR( i , D , c ) {
			L[R[i]] = R[L[i]] = i ;
		}
	}    

	bool vis[maxn] ;  

	int f() {
		int ans = 0 ;
		FOR( i , R , 0 ) vis[i] = true ;
		FOR( i , R , 0 ) {
			if( vis[i] ) {
				vis[i] = false ;
				ans ++ ;
				FOR( j , D , i )
					FOR( k , R , j )
					vis[col[k]] = false ;
			}
		}
		return ans ;
	}  

	bool dfs( int d ) {
		// 剪枝
		if( d + f() > best ) return false ;
		// R[0] = 0 表示找到一个可行解
		if( R[0] == 0 ) return d <= best ;
		// 找到 s 最小的列 , 加快搜索的速度
		int c = R[0] ;
		FOR( i , R , 0 )
			if( S[i] < S[c] ) c = i ;
		FOR( i , D , c ) {
			remove(i);
			FOR( j , R , i ) remove( j );
			if (dfs(d + 1))
				return true ;
			FOR( j , R , i ) restore( j ) ;
			restore( i ) ;
		}
		return false ;
	}    

	bool solve( int k ) {
		best = k ;
		return dfs(0) ;
	}
	int best ;
} dlx ;    

int n , m , k ;
__int64 ABS( __int64 x ) {
	return x  < 0 ? -x : x ;
}

struct Point{
	__int64 x , y ;
	void get(){
		scanf( "%I64d%I64d" , &x , &y ) ;
	}  

	friend __int64 dist ( const Point &a  , const Point & b ) {
		return ABS( a.x - b.x ) + ABS ( a.y - b.y ) ;
	}
};  

Point city[65] ;  

__int64 dis[60*60+10] ;

int lisanhua( int Index ) {
	int cnt = 1 ;
	for( int i = 1 ; i < Index ; i ++ ) {
		if( dis[i] != dis[i-1] )
			dis[cnt++] = dis[i] ;
	}
	return cnt - 1 ;
}

int main(){
	int cas ;
	int casn = 1 ;
	scanf( "%d" , &cas ) ;
	while( cas -- ) {
		scanf( "%d%d" , &n, &k ) ;
		for( int i = 1 ; i <= n ; i ++ ) {
			city[i].get() ;
		}
		int Index = 0 ;
		for( int i = 1 ; i <= n ; i ++ ) {
			for( int j = i ; j <= n ; j ++ ) {
				dis[Index++] = dist( city[i] , city[j] ) ;
			}
		}
		sort( dis , dis + Index ) ;
		Index = lisanhua( Index ) ;
		__int64 l = 0 , r = Index ;
		__int64 mid ;
		while( l < r ) {
			mid = ( l + r ) / 2 ;
			dlx.init( n ) ;
			for( int i = 1 ; i <= n ; i ++ ) {
				for( int j = 1 ; j <= n ; j ++ ) {
					if( dist( city[i] , city[j] ) <= dis[mid] ) {
						dlx.Link( i , j ) ;
					}
				}
			}
			if( dlx.solve( k ) ) {
				r = mid ;
			}else{
				l = mid + 1 ;
			}
		}
		printf( "Case #%d: %I64d\n" , casn ++ , dis[l] ) ;
	}
	return 0 ;
}  
时间: 2024-10-17 01:28:29

HDU 5046 Airport ( Dancing Links 重复覆盖 )的相关文章

HDU 5046 Airport ( Dancing Links 反复覆盖 )

今年上海网络赛的一道题目 , 跟 HDU 2295 如出一辙 . 就是距离的计算一个是欧几里得距离 , 一个是曼哈顿距离 学完DLX感觉这题好水 ,就是一个裸的反复覆盖 注意下别溢出即可了 #include <stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <math.h> #include <stdlib.h> using na

HDU5046 Airport dancing links 重复覆盖+二分

这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮点,这里是整数 我写的一个比较暴力 #include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector

HDU 5046 Airport(DLX重复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场,要求选出K个机场,使得其他机场到其他机场的最大值最小 思路:二分+DLX重复覆盖去判断即可 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

HDU 3335 Divisibility dancing links 重复覆盖

分析: dlx重复覆盖的巧用,重复覆盖的原理恰好符合本题的筛选方式,即选择一个数后,该数的倍数或约数可以保证在之后的搜索中不会被选择 于是修改一下启发函数,求解最大的重复覆盖即可. 其实不一定不被选择,只是选择以后,要么达不成目标,要不达到目标,也不如不选择更优 举下面的例子 3 2 3 6 答案一看就是 2 初始的dancing links的表示是这样的 2   3   6 2    1   0   1 3    0   1   1 6    1   1   1 然后肯定先选第一列进行删 删

HDU 5046 Airport(DLX反复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场.要求选出K个机场,使得其它机场到其它机场的最大值最小 思路:二分+DLX反复覆盖去推断就可以 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

HDU 2295 Radar( 二分+Dancing Links重复覆盖 )

题意 : 有 n 个城市 , m个站 , 你要选择 k 个站 , 每个站画一个半径为 r 的圆 , 可以覆盖所有的城市 , 一个城市可以被多个站覆盖 .求的是满足要求的最小的 r . 思路很明显了 , 首先是二分 , 将问题转化成可行性判定的问题 . 那么对于 mid , 我们将 站看成行 , 将城市看成 列 , 如果一个站和一个城市的距离小于mid , 那么对应的矩阵位置的值就1 , 否则是0 , 用dlx 重复覆盖来解决 重复覆盖和精确覆盖主要有两个区别 : 第一, remove 和 res

HDU 5046 Airport(DLX可重复覆盖)

Problem Description 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 dij = |xi - xj| + |yi - yj|. jiuye want

hihoCoder #1321 : 搜索五?数独 (Dancing Links ,精确覆盖)

hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. 提示已经讲解的很清楚了.稍微整理下思路.最后附AC代码. 一.Dancing Links解决精确覆盖问题.      1.精确覆盖问题         给定一个n行,m列的01矩阵.从中选择若干行使得每一列有且恰好只有一个1. 例如: 答案是选择2,3,4行. 2.DancingLinks求解精确

hdu 5046 Airport

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5046 2014 ACM/ICPC Asia Regional Shanghai Online的题,DLX重复覆盖.. 虽然不放在DLX专题我都看不出来.. 二分距离,判断条件就是K个城市能不能满足条件. #include <iostream> #include <cstring> #include <set> #include <cstdio> #include &