题目来源:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=100
现在换一种方式来写这个状态压缩
我们先把第0行铺满,然而其余每一行的状态都可以由前一种状态转移而来。我们令第0层全部铺满,只有一种情况,当0 <= i < row时,我们有如下方程:
第0行铺满的状态为(1<<col)-1,铺设方案我们假设为1种,实际上达到(1<<col)-1这种状态,有多种铺设方案,那么就有多种第0行的状态我们可以转移到第1行的状态,由此来计算到第1行时的铺设方案数(第0行的每一种可到达状态(1<<col)-1的铺设方案数都为1,因此有上面的状态转移方程可计算出第一行的所有合法的铺设状态,以及铺设方案数),然后依次类推。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int nTran;
double b[13][2050];//表示每一行的合理放置方案数
int tran[14000][2];//tran[j][0]表示当前行的放置状态,tran[j][0]表示下一行的放置方案
int row, col;
//只搜索第0行的所有放置方案
void DFS(int CurNum, int from, int to)//curNum表示左边CurNum个格子的放置方案
{
if(CurNum > col)
return ;
if(CurNum == col)
{
tran[nTran][0] = from;
tran[nTran++][1] = to;
return ;
}
DFS(CurNum+2, from<<2|3, to<<2|3);//水平放置
DFS(CurNum+1, from<<1|1, to<<1);//竖直放置
DFS(CurNum+1, from<<1, to<<1|1);//不放置
}
void DP()
{
int i, j;
memset(b, 0x00, sizeof(b));
b[0][(1<<col)-1] = 1;
for(i = 0; i < row; ++i)
for(j = 0; j < nTran; ++j)
b[i+1][tran[j][1]] += b[i][tran[j][0]];//每一行的合理放置状态是由前一行的状态转移过来的
}
int main()
{
while(scanf("%d %d", &row, &col) && (row+col))
{
if(row < col)
{
row ^= col;
col ^= row;
row ^= col;
}
nTran = 0;
DFS(0, 0, 0);
DP();
printf("%0.f\n", b[row][(1<<col)-1]);
}
return 0;
}