HDU 2442 Bricks

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;
}
原文地址:https://www.cnblogs.com/staginner/p/2671237.html