POJ 1185 炮兵阵地(状态压缩DP)

题意:

求最大的炮兵摆放数量,并且使他们之间不相互误伤。

NOI 01 的题目。

思路:

1. 和 POJ 1038 类似,把行看成是一个整体,每一种摆放代表着一种状态,r-2, r-1 行的状态决定着 r 行的状态;

2. 本题状态比较稀疏,所以提前处理下炮兵的摆放无意是比较好的选择,由于没两个炮兵之间至少相距为 2,利用这个把每一行的炮兵可能摆放情况存放起来;

3. dp[r][i][j] 表示第 r 行的状态为 i 且第 r-1 行的状态为 j 时,所能摆放的最大炮兵数量,同时还需要枚举 r-2 行的炮兵摆放情况;

4. 最终有状态转移方程: dp[r][i][j] = max(dp[r][i][j], dp[r-1][j][k] + men[i]); 并且要求 dp[r-1][j][k] 存在,且 r 行能保证能摆放 i 状态;

5. 有了 POJ 1038 和 POJ 1185 的积累,我想以后做此类基于摆放的状态压缩 DP 应该能够有个比较清晰的思路了。

 

#include <iostream>
#include <algorithm>
using namespace std;

int row, col;
int state[60], cnt, men[60], mapstate[110];
bool grid[110][12];
int dp[2][60][60];

bool judge(int s) {
    if (s & (s<<1))
        return false;
    if (s & (s<<2))
        return false;
    return true;
}

int calcmen(int s) {
    int ans = 0;
    while (s) {
        ans += 1;
        s &= (s-1);
    }
    return ans;
}

void initstate(int endstate) {
    cnt = 0;
    for (int s = 0; s < endstate; s++) {
        if (judge(s)) {
            state[cnt] = s;
            men[cnt] = calcmen(s);
            cnt += 1;
        }
    }
}

int solvedp() {
    memset(dp[0], -1, sizeof(dp[0]));
    for (int i = 0; i < cnt; i++) {
        if (mapstate[0] & state[i])
            continue;
        dp[0][i][0] = men[i];
    }
    int T1 = 1, T2 = 0;
    for (int r = 1; r < row; r++) {
        T1 ^= 1, T2 ^= 1;
        memset(dp[T2], -1, sizeof(dp[0]));
        for (int i = 0; i < cnt; i++) {
            if (state[i] & mapstate[r]) 
                continue;
            for (int j = 0; j < cnt; j++) {
                if ((state[i] & state[j]) || (state[j] & mapstate[r-1]))
                    continue;
                for (int k = 0; k < cnt; k++) {
                    if ((state[i] & state[k]) || (state[k] & state[j]))
                        continue;
                    if (dp[T1][j][k] != -1)
                        dp[T2][i][j] = max(dp[T2][i][j], dp[T1][j][k]+men[i]);
                }
            }
        }
    }
    int ans = -1;
    for (int i = 0; i < cnt; i++)
        for (int j = 0; j < cnt; j++)
            ans = max(ans, dp[T2][i][j]);
    return ans;
}

int main() {
    scanf("%d%d", &row, &col);
    for (int i = 0; i < row; i++) {
        char s[20];
        scanf("%s", s);
        mapstate[i] = 0;
        for (int j = 0; j < col; j++) {
            mapstate[i] <<= 1;
            mapstate[i] |= s[j] == 'H' ? 1 : 0;
        }
    }
    initstate(1<<col);
    printf("%d\n", solvedp());
    return 0;
}
posted @ 2013-04-05 22:00  kedebug  阅读(571)  评论(0编辑  收藏  举报