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; }