poj1185炮兵阵地

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

using namespace std;

const int MAXN = 100 + 1;       //阵地行数
const int MAXM = 10 + 1;        //阵地列数
const int State_Num = 60 + 1;   //阵地列状态的压缩总数,合法状态总数最多60

int dp[MAXN][State_Num][State_Num], cur[MAXN], state[State_Num], tot;
char field[MAXN][MAXM];    //储存阵地
int n, m;    //阵地规模

/*
因为n <= 100, m <= 10,将阵地的列压缩。
dp[i][j][k]表示当第i行布置结束后,第i行的布置状态为j的情况下,
第i - 1行的状态为k,所能布置的最多的炮兵。

依据题意,我们能够删除一些状态。 删除的状态有: 1.山地不能布置炮兵 2.炮兵不能在垂直和水平的线上两格相邻。 cur[]数组用于储存输入的合法局面 state[]数组用于储存相邻的合法局面 */ bool ok(int x) { return !((x & (x << 1)) || (x & (x << 2))); } void init() //保留不两格相邻的 { int limit = (1 << m); tot = 0; for (int i = 0; i < limit; i++) { if (ok(i)) state[tot++] = i; } } bool yes(int x, int i) { return !(x & cur[i]); } int cal(int x) { int res = 0; while (x) { if (x & 1) res++; x >>= 1; } return res; } void input() { while (scanf("%d %d", &n, &m) != EOF) //输入 { init(); memset(dp, 0, sizeof(dp)); for (int i = 0; i < n; i++) { scanf("%s", field[i]), cur[i] = 0; for (int j = 0; j < m; j++) if (field[i][j] == 'H') cur[i] += (1 << (m - j - 1)); //用于推断状态是否合法(1) } for (int i = 0; i < tot; i++) //初始化第一行 { if (!yes(state[i], 0)) continue; for (int j = 0; j < tot; j++) { dp[0][i][j] = cal(state[i]); } } for (int i = 1; i < n; i++) //计算当前行,枚举上两行的状态 { for (int j = 0; j < tot; j++) //枚举当前行的状态 { if (!yes(state[j], i)) continue; for (int k = 0; k < tot; k++) { if (!yes(state[k], i - 1)) continue; for (int l = 0; l < tot; l++) { if (!yes(state[l], i - 2)) continue; if (((state[j] & state[k]) == 0) && ((state[j] & state[l]) == 0) && ((state[k] & state[l]) == 0)) { dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][l] + cal(state[j])); } } } } } int ans = 0; //计算答案 for (int i = 0; i < tot; i++) for (int j = 0; j < tot; j++) ans = max(ans, dp[n - 1][i][j]); cout << ans << endl; } } int main() { input(); return 0; }


posted @ 2016-01-19 17:07  mengfanrong  阅读(142)  评论(0编辑  收藏  举报