炮兵阵地(压状经典题)

题目描述:

炮兵阵地
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 38992   Accepted: 14874

Description

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

Input

第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

Output

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output

6
思路:已经是二刷了,一刷的时候递推用的是用的前面第二层来推,但是前二层的最优解可能会导致中间的有些状态不能选择,所以应该用上一层的最优解来推,这里就不多废话了
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<math.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = 20;
int n, m;
int cnt = 0;
struct node {
    int now, num;
}book[80];
int dp[2][80][80];
void dfs(int pos, int now, int num) {
    if (pos >= m) {
        book[cnt++] = { now,num };
        return;
    }
    dfs(pos + 1, now, num);//不放炮兵
    dfs(pos + 3, now + (1 << pos), num + 1);//该位置放炮兵
}
int donot[100];
char t;
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d%d", &n, &m);
    dfs(0, 0, 0);//预处理求出一层所有状态,存到book中,并且输出cnt发现是60左右,非常小,所以我开到80就可以了
    //cout << cnt << endl;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> t;
            if (t == 'H')//把不可选的位置用二进制储存
                donot[i] |= (1 << j);
        }
    }
    int f = 1;
    int ans = 0;
    if (n == 1) {//特判
        for (int i = 0; i < cnt; i++) {
            if (book[i].now & donot[0])continue;
            ans = max(ans, book[i].num);
        }
        cout << ans << endl;
        return 0;
    }
    for (int i = 0; i < cnt; i++) {
        if (book[i].now & donot[1])continue;//不可放
        for (int j = 0; j < cnt; j++) {
            if (book[j].now & donot[0])continue;
            if (book[i].now & book[j].now)continue;//垂直方向有相同不可选
            dp[f][i][j] = book[i].num + book[j].num;
        }
    }
    for (int s = 2; s <n; s++) {
        f ^= 1;
        memset(dp[f], 0, sizeof(dp[f]));//滚动数组优化内存
        for (int i = 0; i < cnt; i++) {
            if (book[i].now & donot[s])continue;
            for (int j = 0; j < cnt; j++) {
                if (book[j].now & donot[s - 1])continue;
                if (book[i].now & book[j].now)continue;
                for (int k = 0; k < cnt; k++) {
                    if (book[k].now & donot[s - 2])continue;
                    if (book[i].now & book[k].now)continue;
                    if (book[j].now & book[k].now)continue;
                    dp[f][i][j] = max(dp[f][i][j], dp[f ^ 1][j][k] + book[i].num);
                }
            }
        }
    }
    for (int i = 0; i < cnt; i++) {
        if (book[i].now & donot[n - 1])continue;
        for (int j = 0; j < cnt; j++) {
            if (book[j].now & donot[n - 2])continue;
            if (book[j].now & book[i].now)continue;
            ans = max(ans, dp[f][i][j]);
        }
    }
    cout << ans << endl;
    return 0;
}

 

 
posted @ 2021-03-16 19:42  cono奇犽哒  阅读(92)  评论(0)    收藏  举报