[编程题]小军砌墙 难得离谱 讲的明白 位运算+动态规划

本文介绍了如何使用位运算和动态规划解决一道编程题——小军砌墙。难点在于避免相邻行砖缝对齐,通过位运算高效检查状态。文章提供了一种Golang实现的解决方案,并鼓励读者尝试理解和应用这种方法。

[编程题]小军砌墙 难得离谱 讲的明白 位运算+动态规划

这套题真的难的离谱,2小时做完的都是些什么神仙?

截止5月11日,还没有题解,就让我来抛砖引玉吧。

首先咱们最容易想到的是类似dfs那种递归算法,这个我也贴在后面了,但是超时了。

我重点来讲解下面的 位运算+动态规划 算法。

首先我们来考虑铺一行的可能性,我们定义一个函数f(pos int)来从pos位置开始铺砖,那么:
1.我们可以铺一块2格的红砖,然后调用f(pos+2)
2.我们可以铺一块3格的绿砖,然后调用f(pos+3)

然后在递归搜索的过程中用什么记录状态呢,可以用bool值数组来记录,为1表示一块转结束的位置。
例如 w=9 时可以得到下列状态码:
S1:010101001
S2:010100101
S3:010010101
S4:001010101
S5:001001001

要存储这样的状态码可能最容易想到的是bool数组,但是注意到题干里限制了 2 <= W <= 30,因此咱们可以大胆一点,可以使用int32来作为32位bool来用,省空间是小事,主要是后面我们需要对比两行的间隙,相比与遍历两个bool数组,直接对两个int32进行 位与 效率就高多了。

好了,咱们现在有了铺满9格的5种可行的状态码,那么只有一行的时候每种状态码都只可能出现1次,咱们可以建立一个数组dp[5]来记录每种状态码可能出现的次数,其中每个元素均为1。

那多行呢?题干要求相邻的两行不能出现任何上下对齐的砖缝。
那怎么判断缝隙对没对齐呢?很简单,位与一下。
比如我们当时按S1铺第1行,按S3铺第2行是否符合要求?
只需要将两个状态码 位与,得S:010000001,除了末尾,中间有一处对齐了,因此非法。
如果两个状态码 位与 得S:000000001,则中间没有对齐的缝隙,这个组合是合法的。

进一步,我们可以根据上一行的可能性数组和状态转移来计算。
例如,容易判断S2,S3->S5可行,那么这一行按照S5来铺的可能性等于上一行按S2,S3来铺的可能性之和,实际上就是运用动态规划的思想。

下面是Golang代码,没有什么高级语法,就算你学的Java/Python等应该也都能读懂。

如果这篇解答对你有帮助,不妨点个赞吧!

//位运算+动态规划
package main

import "fmt"

var w,h int

//可行的间隙码
var gaps []int

//铺一行
func f(pos int,gap int){
   
   
	if pos>w{
   
   			//越界
		return
	}else if pos==w{
   
   	//已铺完
		gaps=append(gaps, gap)
	}else{
   
   				//未铺完
		f(pos+2,gap<<2+1)
		f(pos+3,gap<<3+1)
	}
}

func 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值