题目链接 HDU1143
【题意】求出n*3矩阵铺满1*2骨牌的方案数;
【分析】看到别人都推公式的,数学渣不会推,只能用DP了。用dp[i][j]表示前i-1行全部铺满时第i行状态为j时总的方案数,只要枚举所有上一行和当前行能用1*2骨牌铺满的所有状态(可以想像成空缺的地形),然后累加就可以了。
关键还是用dfs生成当前行和上一行的地形(有三中可能):
注意:生成的时候放的骨牌是在第i行放;
1)不放骨牌。为了使得总的地形必须铺满,所以这时生成的上一行必须是已经铺满的,而当前行为空
所以生成状态为 now<<1,last<<1|1;
2)骨牌竖放。为了把骨牌放进去,所以上一行需要是空的,而当前行也必须是空的,所以生成状态为
now<<1|1,last<<1;
3)骨牌横放。这时与上面两种情况不同,因为横放骨牌时会影响到下一列的状态,而我这样是一列一列判断的,但是这时只要直接一下子生成两列即可,因为骨牌要放置在当前行,所以上一行的两格还必须是填满的(否则就永远没机会填满了),至于当前行肯定也要变成填满状态,因为放置了骨牌。所以 now<<2|3,now<<2|3;
【AC CODE】 0ms
/*此方法可以求出宽度小于32的所有可能性*/
#include <cstdio>
#include <cstring>
struct NODE{
int now, last;
}p[13];
int dp[31][8], sum;
void dfs(int now ,int last, int s)//生成出所有可能的两行状态
{
if(s == 3)
{
p[sum].now = now;
p[sum++].last = last;
return;
}
if(s+1 <= 3)
{
dfs(now<<1, last<<1|1,s+1);//不放
dfs(now<<1|1,last<<1,s+1);//竖放
}
if(s+2 <= 3)
dfs(now<<2|3, last<<2|3, s+2);//横放
}
int main()
{
#ifdef SHY
freopen("e:\\1.txt","r",stdin);
#endif
dp[0][7] = 1;
dfs(0,0,0);
for(int i = 1; i <= 30; i++)
{
for(int j = 0; j < sum; j++)
dp[i][p[j].now] += dp[i-1][p[j].last];
}
int n;
while(~scanf("%d%*c", &n) && ~n)
{
printf("%d\n", dp[n][7]);
}
return 0;
}