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;

}

你可能感兴趣的:(poj)