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

题意 :  给你一个大小为 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 ;
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值