狀態壓縮動態規劃 -- 炮兵陣地

weixin_34279184發表於2014-11-05


司令部的將軍們打算在N*M的網格地圖上部署他們的炮兵部隊,一個N*M的地圖由N行M列組成,地圖的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),例如以下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不可以部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所看到的:


假設在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它可以攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其他白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。如今,將軍們規劃怎樣部署炮兵部隊,在防止誤傷的前提下(保證不論什麼兩支炮兵部隊之間不能互相攻擊,即不論什麼一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多可以擺放多少我軍的炮兵部隊。


題目連結:http://poj.org/problem?id=1185


#include <iostream>
#include <cstring>
using namespace std;
#define MAX_SIZE 110
int graph[MAX_SIZE];
int DP[MAX_SIZE][MAX_SIZE][MAX_SIZE];
// DP[raw][i][j] : 在第 raw 行狀態為 i, 第 raw - 1 行狀態為 j 的情況
int pointer, state_stack[MAX_SIZE], ones_num[MAX_SIZE];

// 推斷該狀態左右相鄰兩個單位是否有炮兵衝突
bool isReasonableState( int state ){
    if( state & ( state << 1 ) )
        return false;
    if( state & ( state << 2 ) )
        return false;
    return true;
}

// 計算位元位裡的 1 的個數
int getOnesNum( int state ){
    int num = 0;
    while( state > 0 ){
        if( state & 1 )
            num++;
        state >>= 1;
    }
    return num;
}

// 預處理,統計下全部“行”擺放炮兵的合法狀態
void pretreatment( int cols ){
    int max_state = ( 1 << cols ) - 1;
    for( int state = 0; state <= max_state; ++state ){
        if( isReasonableState( state ) ){
            state_stack[pointer] = state;
            ones_num[pointer]    = getOnesNum( state );
            pointer++;
        }
    }
}

int main(){
    memset( DP, -1, sizeof( DP ) );
    memset( graph, 0, sizeof( graph ) );
    pointer = 0;

    int raws, cols;
    cin >> raws >> cols;
    pretreatment( cols );

    for( int raw = 0; raw < raws; ++raw ){
        for( int col = 0; col < cols; ++col ){
            char c;
            cin >> c;
            if( c == 'H' )
                graph[raw] |= ( 1 << col );
        }
    }

    for( int p = 0; p < pointer; ++p )
        if( !( state_stack[p] & graph[0] ) )
            DP[0][p][0] = ones_num[p];

    for( int raw = 1; raw < raws; ++raw ){
        for( int raw_p = 0; raw_p < pointer; ++raw_p ){
            if( state_stack[raw_p] & graph[raw] )
                continue;
            for( int raw_p_ = 0; raw_p_ < pointer; ++raw_p_  ){
                if( state_stack[raw_p] & state_stack[raw_p_] )
                    continue;
                for( int raw_p__ = 0; raw_p__ < pointer; ++raw_p__ ){
                    if( state_stack[raw_p] & state_stack[raw_p__] )
                        continue;
                    if( DP[raw - 1][raw_p_][raw_p__] == -1 )
                        continue;
                    DP[raw][raw_p][raw_p_] = max( DP[raw][raw_p][raw_p_],
                                            DP[raw - 1][raw_p_][raw_p__] + ones_num[raw_p] );
                }
            }
        }
    }
    int ans = 0;
    for( int raw_p = 0; raw_p < pointer; ++raw_p )
        for( int raw_p_ = 0; raw_p_ < pointer; ++raw_p_ )
            ans = max( ans, DP[raws - 1][raw_p][raw_p_] );

    cout << ans << endl;
    return 0;
}


相關文章