编程之美 4.2 瓷砖覆盖地板 扩展问题

原帖: http://blog.csdn.net/limchiang/article/details/8619611


题意:

用 1 * 2 的瓷砖覆盖 n * m 的地板,问共有多少种覆盖方式? 

思路:
用2进制的01表示不放还是放,第i行只和i-1行有关,枚举i-1行的每个状态,推出由此状态能达到的i行状态:如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态。


然后用dfs搜索在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,直接continue。

状态压缩DP

dp[i][j]表示第i行状态为j时有多少种方法, 

e.g. m=6, i=1, j=15,意味着 第一行瓷砖的状态为 0 0 1 1 1 1. (后四列横向放置了2个瓷砖,但是前2列没放)

那么i=2,第二行瓷砖状态必须是 1 1 x x x x. (x意味着可以放也可以不放,但是前2列状态必须是1, 1 (放置2个竖向瓷砖,以填补第一列的空缺)

#include <stdio.h>
#include <string.h>

/** n * m 的地板 */
int n,m;

/** dp[i][j] = x 表示使第i 行状态为j 的方法总数为x */
__int64 dp[12][2049];

/* 该方法用于搜索某一行的横向放置瓷砖的状态数,并把这些状态累加上row-1 行的出发状态的方法数
 * @name row 行数 
 * @name state 由上一行决定的这一行必须放置竖向瓷砖的地方,s的二进制表示中的1 就是这些地方
 * @name pos 列数
 * @name pre_num row-1 行的出发状态为~s 的方法数
 */ 
void dfs( int row, int state, int pos, __int64 pre_num )
{
	/** 到最后一列  */
	if( pos == m ){
		dp[row][state] += pre_num;
		return;
	}

	/** 该列不放 */
	dfs( row, state, pos + 1, pre_num );

	/** 该列和下一列放置一块横向的瓷砖 */
	if( ( pos <= m-2 ) && !( state & ( 1 << pos ) ) && !( state & ( 1 << ( pos + 1 ) ) ) )
		dfs( row, state | ( 1 << pos ) | ( 1 << ( pos + 1 ) ), pos + 2, pre_num );
}
int main()
{	
	while( scanf("%d%d",&n,&m) && ( n || m ) ){
		/** 对较小的数进行状压,已提高效率 */
		if( n < m ){
			n=n^m;
			m=n^m;
			n=n^m;
		}

		memset( dp, 0, sizeof( dp ) );

		/** 初始化第一行 */
		dfs( 1, 0, 0, 1 );

		for( int i = 2; i <= n; i ++ ) 
			for( int j = 0; j < ( 1 << m ); j ++ ){
				if( dp[i-1][j] ){
					__int64 tmp = dp[i-1][j];

					/* 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,
					 * 所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态
					 */
					dfs( i, ( ~j ) & ( ( 1 << m ) - 1 ), 0, tmp ) ;
				}
				else continue;		
			}

		/** 注意并不是循环i 输出 dp[n][i]中的最大值 */
		printf( "%I64d\n",dp[n][(1<<m)-1] ); 

	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一种可能的实现方法: ```python # 定义瓷砖类型 TILE_TYPES = {'A', 'B', 'C', 'D'} # 定义瓷砖填色函数 def fill_tile(tile_map, row, col, color): # 获取当前位置的瓷砖类型 tile_type = tile_map[row][col] # 如果当前位置已经填过色,或者要填的颜色和当前颜色相同,则直接返回 if tile_map[row][col] == color or tile_map[row][col] == '*': return # 将当前位置填色 tile_map[row][col] = color # 递归填色周围的瓷砖 if row > 0: fill_tile(tile_map, row - 1, col, color) # 上 if row < len(tile_map) - 1: fill_tile(tile_map, row + 1, col, color) # 下 if col > 0: fill_tile(tile_map, row, col - 1, color) # 左 if col < len(tile_map[0]) - 1: fill_tile(tile_map, row, col + 1, color) # 右 # 测试代码 if __name__ == '__main__': # 测试数据 tile_map = [ ['A', 'B', 'A', 'C'], ['B', 'C', 'D', 'A'], ['C', 'D', 'B', 'C'] ] row = 1 col = 2 color = 'E' # 打印原始瓷砖地图 print('Original tile map:') for row in tile_map: print(row) # 填色 fill_tile(tile_map, row, col, color) # 打印填色后的瓷砖地图 print('Tile map after filling:') for row in tile_map: print(row) ``` 在上面的代码中,我们首先定义了瓷砖类型,然后定义了填色函数`fill_tile`。这个函数接受三个参数:瓷砖地图、要填色的行和列、要填的颜色。 在函数中,我们首先获取当前位置的瓷砖类型,如果当前位置已经填过色,或者要填的颜色和当前颜色相同,则直接返回。否则,将当前位置填色,并递归填色周围的瓷砖。这样,我们就可以实现瓷砖填色了。 在测试代码中,我们定义了一个测试瓷砖地图,然后调用`fill_tile`函数进行填色。最后,我们打印填色后的瓷砖地图。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值