poj 1185 炮兵阵地 (状压dp)

思路:网上的解题思路已经有很多了,我就说说我的代码独特的地方。

1.关于这个三维dp的初始化问题,一般的思路就是初始化前两行,但是实际上初始化第1行也是可以的,只需要特判第二行,(然后实践证明不用特判也是行的,因为初始化为了0),本质好像都是一样的。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m, top;
char mp[105][15];
int state[1005];
int dp[105][105][105];//dp[i][j][k]表示第i行状态为k,第i-1行状态为j的时候的总数
int num[105], cur[105];
bool ok(int x) {//判断某一状态是不是合法解
    if(x & (x << 1)) return 0;
    if(x & (x << 2)) return 0;
    return 1;
}
int judge(int x) {//判断某一十进制数的二进制形式有几个1
    int cnt = 0;
    while(x) {
        cnt++;
        x = x & (x - 1);
    }
    return cnt;
}
void init() {//预处理判断所有可行解,以及对应可行解的二进制1的个数(就是放大炮的数量)
    top = 1;
    int sum = 1 << m;
    for(int i = 0; i < sum; i++) {
        if(ok(i)) {
            state[top++] = i;
        }
    }
    for(int i = 1; i <= top; i++) {
        num[i] = judge(state[i]);
    }
}
bool fit(int x, int num) {//判断某一行能否变成对应的可行状态
    if(state[x]&cur[num]) return 0;
    return 1;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(mp[i][j] == 'H') cur[i] += (1 << (m - j));
        }
    }
    init();
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= top; i++) {
        if(fit(i, 1)) dp[1][top][i] = num[i];//top是为能够遍历的到,1也是同样的效果
    }
    for(int i = 2; i <= n; i++) {
        for(int j = 1; j <= top; j++) {
            if(!fit(j, i)) continue;
            for(int k = 1; k <= top; k++) {
                if(!fit(k, i - 1)) continue;
                if(state[j]&state[k]) continue;
                for(int t = 1; t <= top; t++) {
                    if(i != 2) {
                        if(!fit(t, i - 2) ) continue;
                        if(state[t]&state[k]) continue;
                        if(state[t]&state[j]) continue;
                        dp[i][k][j] = max(dp[i][k][j], dp[i - 1][t][k] + num[j]);
                    }//如果当前是第二行,那么其实并不用考虑第二维的值,使用top是为了方便后面的计数,
                    //如果不用top也可以用1,因为1是每次都会存在的,因为每次都会有至少1组可行解
                    else dp[i][k][j] = max(dp[i][k][j], dp[i - 1][top][k] + num[j]);
                }
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= top; i++) {//循环判断最优解
        for(int j = 1; j <= top; j++) {
            ans = max(ans, dp[n][i][j]);
        }
    }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/80539397