POJ #2411

Good reference: http://www.cppblog.com/sdfond/archive/2009/07/31/91761.html

It is a classic coveragedp compression problem. Initially I thought of dp[i][j] (i is row, j is col), but looks like it was not feasible to have a good dp transition function. Instead, the correct way to have dp[i][j] is: i is row still, but j is the state - state is binary representation which is said to be compressed (please check url above). It is just not that easy to figure out the key idea: valid state transition from row i to row i + 1.

First, a recursion procedure is used to compose all valid state transitions - bits by bits. And keep the transition restrictions in mind, we add two more full-state rows: row(0) and row(n+1) to make sure no tile exceeds the limit. At last, we pick row(n+1)(all-1-full-state)'s value which indicates a final valid state. And each dp move means a solution count accumulation.

Really interesting dp problem. And here is the AC code - since i'm still rookie, i just retyped almost everything in the url above :P

//    POJ 2411
//    http://www.cppblog.com/sdfond/archive/2009/07/31/91761.html

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;

#define MAX_N 11
#define MAX_SIZE (1 << MAX_N)
typedef unsigned long long uint64_t;

vector<unsigned> rec[MAX_SIZE];    // s2 -> [s1]: for a dest state s2, recording all its previous valid s1 states
uint64_t dp[MAX_N + 2][MAX_SIZE];

//    Compose all valid s1->s2 transition by making composing every move valid
//    Note: a pattern of combinations by recurrence
void dfs(int col, int s1, int s2, int w, uint64_t MaxState)
{
    if (col >= w)
    {
        if (s1 <= MaxState && s2 <= MaxState)
            rec[s2].push_back(s1);    //    S1->S2 is a valid transition
        return;
    }

    dfs(col + 1, (s1 << 1) | 1, s2 << 1, w, MaxState);
    dfs(col + 1, s1 << 1, (s2 << 1) | 1, w, MaxState);
    dfs(col + 2, (s1 << 2) | 3, (s2 << 2) | 3, w, MaxState);
}

uint64_t calc(int h, int w)
{
    uint64_t MaxState = (1 << w) - 1;

    //    Reset rec
    for (int i = 0; i <= MaxState; i ++)
        rec[i].clear();

    //    DFS precalc - all valid state transitions
    dfs(0, 0, 0, w, MaxState);

    //    Go DP
    dp[0][0] = 1;    // row 0 added to start with
    for (int i = 1; i <= h + 1; i++)    //    each row
    for (uint64_t s = 0; s <= MaxState; s ++)    // each state
    for (int k = 0; k < rec[s].size(); k ++)
    {
        dp[i][s] += dp[i - 1][rec[s][k]];
    }
    return dp[h+1][MaxState];
}

int main()
{
    int w, h;
    while (scanf("%d %d", &h, &w), h && w)
    {
        if (h > w) std::swap(h, w);
        memset(dp, 0, sizeof(dp));
        printf("%llu
", calc(h, w));
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/tonix/p/3828969.html