炮兵阵地

洛谷

简化题意

也可以看成放旗子,但是只能把棋子放到空地上,而且棋子上下各两个不能有其他棋子,左右各两个不能有其他棋子。


思路

\(f_{l,s,i}\) 表示上一行的状态为 l,当前这一行的状态为 s,现在是第 i 行时能放置的最多的炮兵数,那么转移方程可以很容易的推出,\(sum_s\) 表示当前的状态 s 中包含多少个 1。

\(f_{l,s,i} = max(f_{l,s,i}, f[fl,l,i-1]+sum_s)\)

下边只需要判断那里能放那里不能放就行了。

可以用一个数组 \(a_i\) 来表示第 i 行中,山的位置是 1,平地为 0。

判断当前状态有没有在平原上可以直接 \(s \ \& \ a_i\) 就行了。

code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 1030
#define M 110

using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int n, m, ans;
int dp[N][N][3], sum[N], a[M];

int read() {
  int s = 0, f = 0; char ch = getchar();
  while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
  while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
  return f ? -s : s;
}

int main() {
  n = read(), m = read();
  for (int i = 0; i < n; i++) {
    char s;
    for (int j = 0; j < m; j++) {
      cin >> s;
      a[i] <<= 1, a[i] += (s == 'H' ? 1 : 0);
    }
  }
  for (int i = 0; i < (1 << m); i++) {
    int tot = 0, x = i;
    while (x) {
      if (x & 1) tot++;
      x >>= 1;
    }
    sum[i] = tot;
  }
  for (int i = 0; i < (1 << m); i++)
    if (!((i & a[0]) || (i & (i << 1)) || (i & (i << 2))))
      dp[0][i][0] = sum[i];
  for (int l = 0; l < (1 << m); l++)
    for (int s = 0; s < (1 << m); s++)
      if (!((l & s) || (l & a[0]) || (s & a[1]) || (l & (l << 1)) || (l & (l << 2)) || (s & (s << 1)) || (s & (s << 2))))
        dp[l][s][1] = sum[l] + sum[s];
  for (int i = 2; i < n; i++) 
    for (int l = 0; l < (1 << m); l++) {
      if ((l & (l << 1)) || (l & a[i - 1]) || (l & (l << 2))) continue;
      for (int s = 0; s < (1 << m); s++) {
        if ((l & s) || (s & a[i]) || (s & (s << 1)) || (s & (s << 2))) continue;
        for (int fl = 0; fl < (1 << m); fl++) {
          if ((fl & l) || (fl & s) || (fl & a[i - 2]) || (fl & (fl << 1)) || (fl & (fl << 2))) continue;
          dp[l][s][i % 3] = max(dp[l][s][i % 3], dp[fl][l][(i - 1) % 3] + sum[s]);
        }
      }
    }
  for (int l = 0; l < (1 << m); l++) {
    for (int s = 0; s < (1 << m); s++)
      ans = max(ans, dp[l][s][(n - 1) % 3]);
  }
  cout << ans;
}
posted @ 2020-11-12 08:27  Kersen  阅读(166)  评论(0)    收藏  举报