HDU_1400

    借用了一下插头dp中轮廓线的思想,用1表示轮廓线上对应位置是空的,0表示对应位置已经放上了东西,然后逐格进行dp。

    如果递推到当前格子时,上方格子是1,那么这个格子和上一个格子就必须一起放一块竖着的骨牌,否则接下来上面那个格子就不会再填上骨牌了。

    如果递推到当前格子时,上方格子是0,这时看左边的格子,如果是0的话,那么当前这个格子就只能空着了,如果是1的话,那么当前这个格子可以空着,也可以和左边的格子一起放一块横着的骨牌。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXD 15
#define ST 4096
typedef long long LL;
int N, M;
LL f[MAXD][MAXD][ST];
void solve()
{
    int i, j, k;
    for(i = 1; i <= N + 1; i ++)
        for(j = 1; j <= M; j ++)
            for(k = 0; k < (1 << M + 1); k ++) f[i][j][k] = 0;
    f[1][1][0] = 1;
    for(i = 1; i <= N; i ++)
        for(j = 1; j <= M; j ++)
            for(k = 0; k < (1 << M + 1); k ++)
            {
                if(k & 1 << j)
                {
                    if(j < M) f[i][j + 1][k ^ 1 << j] += f[i][j][k];
                    else f[i + 1][1][k ^ 1 << j] += f[i][j][k];
                }
                else
                {
                    if(k & (1 << j - 1))
                    {
                        if(j < M) f[i][j + 1][k ^ 1 << j - 1] += f[i][j][k];
                        else f[i + 1][1][k ^ 1 << j - 1] += f[i][j][k];
                    }
                    if(j < M) f[i][j + 1][k | 1 << j] += f[i][j][k];
                    else f[i + 1][1][k | 1 << j] += f[i][j][k];
                }
            }
    printf("%I64d\n", f[N + 1][1][0]);
}
int main()
{
    while(scanf("%d%d", &N, &M), N)
    {
        if(N < M) std::swap(N, M);
        solve();
    }
    return 0;    
}
posted on 2012-09-04 17:29  Staginner  阅读(550)  评论(0编辑  收藏  举报