ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )

来源:互联网 发布:数据库关联 编辑:程序博客网 时间:2024/04/29 22:58

题意 :  给你一个大小为 n * m 的矩形 , 坐标是( 0 , 0 ) ~ ( n , m )  。然后给你 p 个小矩形 , 坐标是( x1 , y1 ) ~ ( x2 , y2 ) , 你选择最小的几个矩形 , 使得这些矩形可以覆盖整个矩形 , 并且互相不会重叠 。( n , m <= 30 )

思路 : Dancing Links 的精确覆盖问题 。

我们将 n * m 的矩形分成 n * m 个小正方形 ,那么我们只要保证每个小正方形被覆盖且只被覆盖一次即可 。

那么列表示每个小正方形 , 行表示你选择的矩形 , 如果选择这个矩形可以覆盖某个小正方形 , 则对应的格子是1 , 否则对应的格子是 0

最多有 30 * 30 = 900 列 ,最多有 500 行


#include <stdio.h>  #include <string.h>  #include <algorithm>  #include <vector>  using namespace std;  const int maxn = 900 + 10 ;  const int maxr = 500 + 10 ;  const int maxnode = 500 * 900 + 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 ) {  // 删除虚拟结点中的 c 列  L[R[c]] = L[c] ;  R[L[c]] = R[c] ;  // 从 c 列向下遍历  FOR( i , D , c ) {  // 删除遍历到的行  FOR( j , R , i ) {  D[U[j]] = D[j] ;  U[D[j]] = U[j] ;  -- S[col[j]] ;  }  }  }  // 恢复第 c 列  void restore( int c ) {  FOR( i , U , c ) {  FOR( j , L , i ) {  ++S[col[j]] ;  U[D[j]] = D[U[j]] = j ;  }  }  L[R[c]] = R[L[c]] = c ;  }  void dfs( int d ) {// 剪枝if( d >= best ) {return ;}// R[0] = 0 表示找到一个可行解if( R[0] == 0 ) {  best = d ;return ;  }  // 找到 s 最小的列 , 加快搜索的速度  int c = R[0] ;  FOR( i , R , 0 )if( S[i] < S[c] ) c = i ;// 删除第 c 列  remove( c ) ;  // 遍历选中列中有1的行  FOR( i , D , c ) {  ans[d] = row[i] ;  // 删除选中行中有1的列  FOR( j , R , i ) {  remove( col[j] ) ;  }  dfs( d + 1 ) ;  // 回复删除掉的列  FOR( j , L , i ) {  restore( col[j] ) ;  }  }  restore( c ) ;  }  int solve() {  best = INF ;dfs( 0 ) ;if( best == INF ) return -1 ;elsereturn best ;}  int best ;const static int INF = 0x3f3f3f3f ;} dlx ;  int main(){int cas ;scanf( "%d" , &cas ) ;while( cas -- ) {int n , m , p ;scanf( "%d%d%d" , &n , &m , &p ) ;dlx.init( n * m ) ;for( int i = 1 ; i <= p ; i ++ ) {int x1 , y1 , x2 , y2 ;scanf( "%d%d%d%d" , &x1 , &y1 , &x2 , &y2 ) ;for( int x = x1 ; x < x2 ; x ++ ) {for( int y = y1 ; y < y2 ; y ++ ) {dlx.Link( i , x * m + y + 1 ) ;}}}printf( "%d\n" , dlx.solve() ) ;}return 0 ;}





1 0
原创粉丝点击