标签:dlx dancing link
题意 : 给你一个大小为 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 ; else return 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 ; }
ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )
标签:dlx dancing link
原文地址:http://blog.csdn.net/lishaozhe1024/article/details/39758623