HDU_2442
如果用递推形式的dp的话,需要记录两行轮廓线的状态,然后根据状态逐格dp,逐一讨论每个图形是否能够嵌入到当前状态中。
由于写搓了,直接交的时候TLE了,所以就干脆先将所有状态预处理出来了,然后每次O(1)输出正确结果。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXN 110 #define MAXM 6 #define ST 4096 int N, M, D, f[MAXN][MAXM][ST], dp[MAXN][MAXM]; void prepare(int N, int M) { int i, j, k; for(i = 0, D = 1; i < M; i ++) D <<= 2; for(i = 0; i <= N; i ++) for(j = 0; j < M; j ++) for(k = 0; k < D; k ++) f[i][j][k] = 0; f[i][j][0] = 0; for(i = 0; i < N; i ++) { for(j = 0; j < M; j ++) for(k = 0; k < D; k ++) { int st; st = ~(3 << 2 * j) & k | (1 << 2 * j & k) << 1 | 1 << 2 * j; if(j == M - 1) f[i + 1][0][st] = std::max(f[i + 1][0][st], f[i][j][k]); else f[i][j + 1][st] = std::max(f[i][j + 1][st], f[i][j][k]); if(i >= 2 && j < M - 1 && (k >> 2 * j & 7) == 7) { st = k & ~(7 << 2 * j); f[i][j + 1][st] = std::max(f[i][j + 1][st], f[i][j][k] + 4); } if(i >= 2 && j >= 1 && j < M - 1 && (k >> 2 * j - 1 & 15) == 15) { st = k & ~(15 << 2 * j - 1); f[i][j + 1][st] = std::max(f[i][j + 1][st], f[i][j][k] + 5); } if(i >= 1 && j >= 1 && j < M - 1 && (k & 1 << 2 * j - 1) && (k & 1 << 2 * j) && (k & 1 << 2 * j + 2)) { st = k & ~(1 << 2 * j + 1) ^ 1 << 2 * j - 1 ^ 1 << 2 * j ^ 1 << 2 * j + 2; f[i][j + 1][st] = std::max(f[i][j + 1][st], f[i][j][k] + 4); } if(i >= 1 && j < M - 2 && (k & 1 << 2 * j) && (k & 1 << 2 * j + 2) && (k & 1 << 2 * j + 4)) { st = k & ~(1 << 2 * j + 1) ^ 1 << 2 * j ^ 1 << 2 * j + 2 ^ 1 << 2 * j + 4; f[i][j + 1][st] = std::max(f[i][j + 1][st], f[i][j][k] + 4); } if(i >= 2 && j < M - 1 && (k & 1 << 2 * j) && (k & 1 << 2 * j + 1) && (k & 1 << 2 * j + 3)) { st = k ^ 1 << 2 * j ^ 1 << 2 * j + 1 ^ 1 << 2 * j + 3; f[i][j + 1][st] = std::max(f[i][j + 1][st], f[i][j][k] + 4); } } for(k = 0, dp[i][M - 1] = 0; k < D; k ++) dp[i][M - 1] = std::max(dp[i][M - 1], f[i + 1][0][k]); } } int main() { memset(dp, 0, sizeof(dp)); for(int i = 2; i <= 6; i ++) prepare(100, i); while(scanf("%d%d", &N, &M) == 2) { printf("%d\n", dp[N - 1][M - 1]); } return 0; }