POJ1185 炮兵阵地 【状压dp】

题目链接:http://poj.org/problem?id=1185
本题为NOI2001 真题。

题解:
我们先通过预处理(dfs)求出第 i 行的方案数以及方案。
然后判断行、列是否冲突就可以了。

P.S:注意位运算的顺序!被坑了1+h。。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int inf = 1 << 26;

int f[105][105][105], h[105][105], g[105][105], d[105];
char s[105][105];

int n, m;
int tot = 0, ans = 0, sum = 0;

void dfs(int x, int i) {
    if(x >= m) {    // 
        d[i] = ++tot;
        h[i][tot] = ans;    // 方案数 
        g[i][tot] = sum;    // 状态 
        return ;
    }  

    if(s[i][x] == 'P') {
        sum += 1 << x;
        ans ++;
        dfs(x+3, i);
        ans --;
        sum -= 1 << x;
    }

    dfs(x+1, i);
}

int main(){
    scanf("%d %d", &n, &m);
    for ( int i = 1; i <= n; i ++ ) scanf("%s", s[i]);
    for ( int i = 1; i <= n; i ++ ) {
        ans = sum = tot = 0;
        dfs(0, i);
    }
    for ( int i = 1; i <= d[2]; i ++ ) {
        for ( int j = 1; j <= d[1]; j ++ ) {
            if((g[2][i]&g[1][j]) == 0) {
                f[2][i][j] = h[2][i]+h[1][j];
            }
        }
    }

    for ( int i = 3; i <= n; i ++ ) {
        for ( int j = 1; j <= d[i]; j ++ ) {
            for ( int k = 1; k <= d[i-1]; k ++ ) {
                for (int l = 1; l <= d[i-2]; l ++ ) {
                    if((g[i][j]&g[i-1][k]) == 0 && (g[i][j]&g[i-2][l]) == 0 && (g[i-1][k]&g[i-2][l]) == 0) {
                        f[i][j][k] = max(f[i][j][k], f[i-1][k][l]+h[i][j]);
                    }
                } 
            }
        }
    }

    int ans = -1;
    if( n == 1 ) {
        for ( int i = 1; i <= d[n]; i ++ ) {
            ans = max(ans, h[1][i]);
        }
    } else {
        for ( int i = 1; i <= d[n]; i ++ ) {
            for ( int j = 1; j <= d[n-1]; j ++ ) {
                ans = max(ans, f[n][i][j]);
            }
        }
    }
    printf("%d\n", ans);

    return 0;
}
/*
3 4
PHPP
PPHH
PPPP
*/

猜你喜欢

转载自blog.csdn.net/qq_34896694/article/details/69680986