您的位置:首页 > 其它

POJ 2411 Mondriaan's Dream(状态DP)

2016-07-01 12:14 423 查看
题意:求用1*2的牌填满n*m的表格有多少种不同的方法;

用2进制的01表示不放还是放,由于第i行只和i-1行有关,因此可以由i-1行每个状态推出由此状态能够到达的第i行的所有状态。将i-1行任一状态A按位取反后得到第i行的起始状态B。

如 i-1行状态:10011

则 第i行状态:01100

其中第i 行的01100中的1表示竖放在i-1和i的牌。

得到第i行的初始状态B时,用搜索扫一道此初始状态B下横着放牌的所有可能状态,把这些状态累加上i-1行状态A的方法数。

dp[i][j]表示第i行获得状态j的方法数。

dp[i][j] += dp[i-1][k] (k是i-1行中可获得j状态的状态)。

需要明白因为有m列,那么每一行的最多的状况数为(1<< m)-1个。求出每一行的满足的状况时有两种思路:①是经由过程dfs的思路,直接搜刮出所有的可能满足的状况 ②直接暴力列举1-(1<< m)-1所有的状况。当然dfs效率比比例列举要快。

#include<iostream>

const int MaxState = 1 << 12;
const int Maxv = 12;
long long dp[Maxv][MaxState];
long long count;
int h, w;
void dfs(int i, int state, int col_index) {
if (col_index >= w) {
dp[i][state] += count;
return;
}
dfs(i, state, col_index + 1);
if (col_index <= w - 2 && !(state & 1 << col_index) && !(state & 1 << (col_index + 1))) {
dfs(i, state | 1 << col_index | 1 << (col_index + 1), col_index + 2);
}
}

int main() {

while (std::cin >> h >> w, h + w) {
count = 1;
memset(dp, 0, sizeof(dp));
dfs(1, 0, 0);//穷举第一行的所有满足条件的状态

//根据上一行的状态得出当前行的状态
for (int i = 2; i <= h; ++i) {
for (int j = 0; j < (1 << w); ++j) {
if (dp[i-1][j]) {//前一行j这个状态存在
count = dp[i - 1][j];
dfs(i, ~j&((1 << w) - 1), 0);
}

}
}
std::cout << dp[h][(1 << w) - 1] << std::endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: