C++---state compression dp---artillery position (one algorithm per day 2023.4.17)

Note:
This topic is an approximate question titled "State Compression dp-Mondrian's Dream" and "State Compression dp-Little King" and "State Compression dp-Cornfield" . It is recommended to read and understand these three articles first.

Topic:
The generals in the command plan to deploy their artillery units on an N×M grid map.
An N×M map consists of N rows and M columns. Each grid of the map may be a mountain (indicated Hby ) or a plain ( Pindicated by ), as shown in the figure below.

A maximum of one artillery unit can be deployed on each plain terrain (artillery units cannot be deployed on mountainous terrain); the attack range of an artillery unit on the map is shown in the black area in the figure: if marked in gray on the
Please add a picture description
map Deploy an artillery unit on the plain, and the black grid in the picture indicates the area it can attack: two grids on the left and right in the horizontal direction, and two grids in the vertical and vertical directions.
All other white grids on the picture cannot be attacked.
It can be seen from the figure that the attack range of the artillery is not affected by the terrain.

Now, the generals are planning how to deploy the artillery units. On the premise of preventing accidental injury (to ensure that any two artillery units cannot attack each other, that is, any artillery unit is not within the attack range of other artillery units), on the entire map The maximum number of artillery units of our army that can be placed in the area.

Input format
The first line contains two positive integers separated by spaces, representing N and M respectively; the
next N lines each contain consecutive M characters (P or H) without spaces in between. Represents the data for each row in the map in order.

Output format
Only one line, including an integer K, indicating the maximum number of artillery units that can be placed.

Data range
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;
}

Ideas:
It is very similar to the two questions "Little King" and "Corn Field". It is strongly recommended to understand those two questions first.

It is still the classic y-style dp method:
1. Status representation
f[i][j][k] : the
forward iartillery has been placed (including the first irow), and ithe status of the first row is j, and all i-1the plans for the first row are . The attribute is Max (the artillery with the most placement), (the status is / refers to the binary to indicate the placement of the artillery, a common means of suppressing dp),k

jk

2. State calculation
After the baptism of the previous state pressure dp, let's first analyze the "state" and "transition" separately:
1. Under what circumstances is state a (line i) legal?
1. Artillery in a single row cannot attack each other (at most one artillery can exist within three blocks).
Second, artillery cannot be placed on mountainous terrain.

2. Under what circumstances is it legal to transfer state a to state b (line iand line)? One, a and b cannot have artillery in the same column at the same time.i-1

Finally, if the above conditions are met, the state can be transferred.
f[i][a][b] = max(f[i][a][b], f[i-1][b][c] + cnt[a])
From the practical point of view:
1. f[i][a][b] = The first i row has been placed, and the status of row i is a, and the status of row i-1 is b,
2. f[i-1][b][c] = the first i-1 row has been placed, and the status of row i-1 is b, and the status of row i-2 is c, then use 2 to
update 1, you need to add the number of artillery placed in the current state a.

If it is helpful, please give a free like~ Someone watching is the motivation to support me to write down!

Disclaimer:
The source of the algorithm idea is Mr. Y. For details, please refer to https://www.acwing.com/
This article is only used for learning records and exchanges

Guess you like

Origin blog.csdn.net/SRestia/article/details/130208667