可以把一个难以描述的状态压缩为一个二进制数,即将状态用一个数字表示
例题:
- 给定一个n*m的方格,每次可以填一个1*2或2*1的矩形,若要将其填满,共有多少种填法(1<=n<=5, 1<=m<=1000)
分析:
- 因为n的范围很小,所以我们可以把每一列都用一个二进制数表示,作为一个状态,则dp[i][j]表示前i列,第i列的装态为j时的最大填法数
- 用dfs(i, j, now, next)表示深搜第i列,第j行,而第i列的状态为now,因为如果填1*2的矩形,则会对后面的状态有影响,所以用next记录对后面的影响
- 当j==n即第i列已经讨论完时,给d[i+1][next]的值加上dp[i][now]的值
下面是代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 2000 + 10;
int n, m;
int dp[MAXN][MAXN]; //dp[i][j]表示讨论到了第i列,当前列的状态是j时的方式数 d[i][j] = sum(d[i-1][1~1<<n])
void dfs(int i, int j, int now, int next) //第i列,当前讨论到第i列的第j个,当前列的状态为now,这一列对下一列影响后下一列的状态为next
{
if(j == n)
{
dp[i+1][next] += dp[i][now]; //这一列讨论完后更新下一列的dp值
return ;
}
if( ((1<<j)&now) )
dfs(i, j+1, now, next);
if( !((1<<j)&now) )
dfs(i, j+1, now, next|(1<<j));
if( (j+1) < n && !((1<<j)&now) && !(( 1<<(j+1) )&now) )
dfs(i, j+2, now, next);
return ;
}
int main()
{
cin >> n >> m;
dp[1][0] = 1;
for(int i = 1; i <= m; i++)
for(int j = 0; j < (1<<n); j++)
if(dp[i][j]) dfs(i, 0, j, 0);
cout << dp[m+1][0];
return 0;
}