C++---상태 압축 dp---포병 위치(2023.4.17 하루에 하나의 알고리즘)

참고:
이 항목은 "State Compression dp-Mondrian's Dream""State Compression dp-Little King""State Compression dp-Cornfield" 라는 제목의 대략적인 질문 입니다. 이 세 기사를 먼저 읽고 이해하는 것이 좋습니다.

주제:
사령부의 장군은 포병 부대를 N×M 그리드 맵에 배치할 계획입니다. N×M 지도는 N개의 행과 M개의 열로 구성되며 지도의 각 그리드는 아래 그림과 같이
산( H로 .P

포병부대는 평지형 1개당 최대 1개까지 배치할 수 있으며(산악지대에는 포병부대 배치 불가) 지도상의 포병부대의 공격 범위는 그림의 검은색 부분으로 표시된다.
사진 설명을 추가해주세요
지도 평야에 포병 유닛을 배치하고 그림의 검은색 격자는 공격할 수 있는 영역을 나타냅니다. 가로 방향으로 좌우에 2개의 격자, 세로 및 세로 방향으로 2개의 격자가 있습니다.
그림의 다른 모든 흰색 격자는 공격할 수 없습니다.
포병의 공격 범위가 지형에 영향을 받지 않는다는 것을 그림에서 알 수 있습니다.

이제 장성들은 포병 부대의 배치 방법을 계획하고 있는데 우발적 부상 방지를 전제로 (두 개의 포병 부대가 서로 공격할 수 없도록, 즉 어떤 포병 부대도 다른 포병 부대의 공격 범위 내에 있지 않도록 하기 위해) , 전체지도에서 해당 지역에 배치 할 수있는 우리 군대의 최대 포병 유닛 수입니다.

입력 형식
첫 번째 줄에는 각각 N과 M을 나타내는 공백으로 구분된 두 개의 양의 정수가 포함되며,
다음 N줄에는 각각 공백 없이 연속적인 M 문자(P 또는 H)가 포함됩니다. 맵의 각 행에 대한 데이터를 순서대로 나타냅니다.

출력 형식 배치
할 수 있는 포병 유닛의 최대 수를 나타내는 정수 K를 포함하여 한 줄만 표시됩니다.

데이터 범위
N≤100, M≤10

输入:
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
输出:
6

#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 110, M = 1 << 10;
int n, m, cnt[M], st[N], f[2][M][M];
char t;
vector<int> state, state_trans[M];


bool check(int s) {
    
         //判断同一行中,三格内只能同时存在一个1,也就是炮兵不能互相攻击到为合法状态,
    for (int i = 0; i<m; i++) {
    
    
        if ((s >> i & 1) && ((s >> (i+1) & 1) | (s >> (i+2) & 1))) return false;
    }
    return true;
}
int count(int s) {
    
          //计算当前状态中1的数量
    int res = 0;
    for (int i = 0; i<m; i++) res += (s >> i & 1);
    return res;
}

int main() {
    
    
    cin >> n >> m;

    //预处理所有读入,将每一行的地势转换为二进制,1为山地,0为平原
    for (int i = 1; i<=n; i++) {
    
    
        for (int j = 0; j<m; j++) {
    
    
            cin >> t;
            st[i] += ((t=='H') << j);
        }
    }

    //预处理所有合法状态
    for (int i = 0; i < (1 << m); i++) {
    
    
        if (check(i)) {
    
    
            state.push_back(i);
            cnt[i] = count(i);
        }
    }

    //预处理所有合法状态转移, 本题行与行之间的限制就是不能在同一列摆放炮兵
    for (auto &a : state) {
    
    
        for (auto &b : state) {
    
    
            if ((a&b)==0) state_trans[a].push_back(b);
        }
    }

    //dp
    for (int i = 1; i<=n+2; i++) {
    
              //枚举地图的每一行,
        for (auto &a : state) {
    
           //枚举所有合法状态a(第i层)
            if ((a & st[i])==0) {
    
               //当状态a没有在山地上部署的炮兵,那就可以进行状态转移,=
                for (auto &b : state_trans[a]) {
    
            //枚举所有能从a转移到的状态b,(第i-1层)
                    for (auto &c : state_trans[b]) {
    
        //枚举所有能从b转移到的状态c,(第i-2层)
                        if ((a&c)==0) {
    
                 //a能转移到b,b能转移到c,但不代表a能转移到c(比如a=010,b=001,c=110,a-b合法,b-c合法,a-c不合法)
                            f[i&1][a][b] = max(f[i&1][a][b], f[(i-1)&1][b][c] + cnt[a]);
                        }
                    }
                }
            }
        }
    }

    //这里还是和之前的状压dp一样,n+2是小优化,表示:前n+2行已经摆完,且第n+2行状态为0(一个炮兵不摆),第n+1行状态为0,
    //那么就和sum(f[n][1~m][1~m])的方案数是一样的。
    cout << f[(n+2)&1][0][0];
    return 0;
}

아이디어:
"작은 왕"과 "옥수수 밭"이라는 두 가지 질문과 매우 유사합니다. 이 두 가지 질문을 먼저 이해하는 것이 좋습니다.

여전히 고전적인 y-스타일 dp 방법입니다.
1. 상태 표시
f[i][j][k] :
전방 i포병이 설정되었으며(첫 번째 i행 포함), i첫 번째 행의 상태는 이고 j, 첫 번째 행의 모든 i-1​​계획은 입니다 . 속성은 Max(가장 많이 배치된 포병), (상태는 dp 를 억제하는 일반적인 수단인 포병의 배치를 나타내는 바이너리를 나타냅니다),k

jk

2. 상태 계산
이전 상태 압력 dp의 세례 후 먼저 "상태"와 "전환"을 별도로 분석해 보겠습니다.
1. 어떤 상황에서 i상태(라인)가 합법적입니까?
1. 한 줄에 있는 포병은 서로 공격할 수 없습니다(세 블록 내에 최대 1개의 포병이 존재할 수 있음).
둘째, 대포는 산에 배치할 수 없습니다.

2. 어떤 상황에서 상태 a를 상태 b로 이전하는 것이 합법적입니까 (라인 i및 라인)? 하나, a와 b는 동시에 같은 열에 포병을 가질 수 없습니다.i-1

마지막으로 위의 조건이 충족되면 상태를 이전할 수 있습니다.
f[i][a][b] = max(f[i][a][b], f[i-1][b][c] + cnt[a])
실용적인 관점에서:
1. f[i][a][b] = 첫 번째 i 행이 배치되었으며 i 행의 상태는 다음과 같습니다. a이고, i-1행의 상태는 b,
2. f[i-1][b][c] = 첫 번째 i-1행이 배치되었고, i-1행의 상태는 b이고, 행 i-2의 상태는 c이고 2를 사용하여
1을 업데이트하면 현재 상태 a에 배치된 포병의 수를 추가해야 합니다.

도움이 되셨다면 무료 좋아요 부탁드려요~ 누군가 지켜봐주셔서 글을 쓰게 된 원동력이 되었어요!

면책 조항:
알고리즘 아이디어의 출처는 Mr.Y입니다. 자세한 내용은 https://www.acwing.com/을 참조하십시오.
이 기사는 학습 기록 및 교환에만 사용됩니다.

추천

출처blog.csdn.net/SRestia/article/details/130208667