插头dp

190 篇文章 2 订阅
84 篇文章 2 订阅

解释

是状压dp的一种,主要是维护一条轮廓线,然后逐个格子进行转移,一般是用来维护连通性(每一个格子记录它与上下左右哪些格子相连),但也可以做其他问题。

题面

题意

给出m*n的矩形,问用1 *2的小矩形填满共有几种方法。

方法

此题首先可以逐行递推,枚举两行可以转移的状态,详见状压dp解法,还可以用插头dp的方法,逐个格子递推,具体见图:
转移过程
蓝色表示当前考虑的格子,红色表示此时记录的状态,本质上就是一个格子一个格子覆盖过去,若已经覆盖则直接转移到下一个状态,反之则覆盖上能盖的并更新状态。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;

ll n,m,dp[20][20][2050];

int main()
{
	register ll i,j,k;
	while(~scanf("%lld%lld",&m,&n))
	{
		if(!m&&!n) return 0;
		memset(dp,0,sizeof(dp));
		dp[1][1][0]=1;
		for(i=1;i<=m;++i)
		{
			for(j=1;j<=n;++j)
			{
				for(k=0;k<=(1 << n)-1;++k)
				{
					if(!dp[i][j][k]) continue;
					if(k&(1 << (j-1)))
					{
						if(j!=n)
							dp[i][j+1][k^(1 << (j-1))]+=dp[i][j][k];
						else
							dp[i+1][1][k^(1 << (j-1))]+=dp[i][j][k];
						continue;
					}
					if(j<n-1)
					{
						if(!(k&(1 << j)))
							dp[i][j+2][k]+=dp[i][j][k];
					}
					else if(j==n-1)
					{
						if(!(k&(1 << j)))
							dp[i+1][1][k]+=dp[i][j][k];
					}
					if(j!=n)
					{
						dp[i][j+1][k|(1 << (j-1))]+=dp[i][j][k];
					}
					else
					{
						dp[i+1][1][k|(1 << (j-1))]+=dp[i][j][k];
					}
				}
			}
		}
		printf("%lld\n",dp[m+1][1][0]);
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值