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
*/