插头DP-2

POJ 2411 Mondriaan’s Dream
1*2砖填充矩形,问多少种方法

#include<bits/stdc++.h>
using namespace std;
long long dp[2][1<<11];
int main(){
	int n,m;
	while(scanf("%d%d",&n,&m),(n||m)){//输入行列数且两个数都非零
		int total=1<<m;//total是2^(m+1),即开了M个位,现在是格转移
		int pre=0,now=1;//设置PAST与NOW互换
		memset(dp[now],0,sizeof(dp[now]));//多组样例要清零
		dp[now][0]=1;//当前点全部位置都下一列都可以放砖
        //用1表示该处竖着放一块砖,下一行此处不可以放砖
        //用0表示横着放的砖第一列,或者竖着放的第二行,下一行此处可以放砖
		for(int i=0;i<n;i++)//遍历行
			for(int j=0;j<m;j++){//遍历列
			swap(now,pre);//行列交换把上一次的NOW值变成PRE
			memset(dp[now],0,sizeof(dp[now]));//把这次的NOW对应的DP数组清零
			for(int S=0;S<total;S++) //枚举状态
                if(dp[pre][S]){//上一个点这种状态的方案数非零,下面三行精华
                    dp[now][S^(1<<j)]+=dp[pre][S];//首先是打竖摆的方案递推
                    //上次状态当前J列是1则表示本次不能放砖,故此位改为0表该处竖着放一块砖且为第二行
                    //上次状态当前J列是0则表示本次可以放砖,故此位改为1表该处竖着放一块砖且为第一行
                    //关键一点:一个位跟1进行异或就是取反,故代码意为S的J列位取反
                    if( j && S&(1<<(j-1)) && !(S&(1<<j)) )//然后是打横摆的方案递推
                        //j列不是第一列
                        //当前状态下J-1位是1,即左边的格已被占
                        //当前状态下J位是0,即当前可以放砖
                        dp[now][S^(1<<(j-1))]+=dp[pre][S];//其实上面已经保证(1<<(j-1))是1
                        //本次S的j-1位清0表示该处横着放一块砖且为第一列
                }
		}
		printf("%lld\n",dp[now][0]);//输出现在的点(最后一个)轮廓线状态全为0的方案数
	}
}
/*
样例输入 输出
2 2		 2
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值