説明
コマンド将軍はN * Mのグリッドマップ上の自分の大砲を配備する予定 以下に示すようにN * Mは、N行M列からなるマップであり、各セルは(「H」で示す)山のマップであってもよく、それは普通であってもよい、(「P」で示されます)。(いない山に配布大砲に)普通地形大砲に各セル上に配置することができ、このような黒い領域に示すマップ上の範囲砲攻撃:
同一の地図上の灰色の場合左右横枠に沿って2つずつ、二つのセルまでの長手方向のダウン:プレーン大砲の展開は、図は、攻撃することができる領域に黒のグリッドを表します。この図は、他の白のグリッドを攻撃していませんでした。マップからの地形の範囲に対する砲撃の目に見える効果。
今、将軍が傷害を防止する前提の下で、大砲を展開する方法を計画していたマップ全体(保証は、いずれかの砲兵部隊が攻撃他の砲兵支援の範囲内ではない任意の2つの砲兵ユニット、間お互いを攻撃していません)軍の砲兵ユニットの最大数は、エリア内に配置することができます。
入力
;最初の行は、2つの正の整数スペースそれぞれ離れて、N及びMによって分離含ま
ないスペースで、次のN行、M連続した文字(「P」または「H」)を含む各行。各ラインのマップを表す順序データ。N <= 100; M <= 10。
出力
唯一のラインは、整数Kを含有する大砲の配置する数を表します。
サンプル入力
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
サンプル出力
6
問題の解決策
- まず、データの範囲を簡単に見られる形態圧DP
- この質問とコーンフィールド(オリジナルのタイトル&説明を見るためにリンクをクリックしてください)のように、この質問を
- 殻の範囲が2であるので、二列の状態は、DP次元アレイも増加させる必要性を列挙する。
- 定義: DP [I] [J] [K]:i番目の行ときに状態j、回線状態の力の最大数場合K
- 平野:1;山:0
- 同様に、私たちは前処理を必要とするもの:入力された場合には、各ラインの変換小数点以下のステータスがアップし、保存やニーズが一列に記録されるように、条件状態(任意の横力のない2は、お互いを打ちます)。ノートは、しかし、トピックの範囲に応じて、ここで1 << 10、意志直接オープンDP MLE配列は、原因2、唯一の60未満の症例からの攻撃に実際にあります。
- この質問は、軍の最大数を求めているので、その方法について事前に求めているとき、それぞれの状態1(無地)番号を
- 状態遷移方程式:DP [I-行] [状態j] = MAX(DP [回線状態k上] [I] [J] [K]、[ライン上:I-1] DPライン上の[状態k] [オン状態T] +数(フラット)状態j 1)。
- 列挙各ラインの状態、入力のサブセットを許可するかどうかを決定し、競合のためのアップリンクおよびダウンリンクを覚え
- 最後に、あなたは最大走行側を取ることができます
ご注意ください
- まだ非常に満足のいく形圧力DP、非常に単純な
- 唯一の60をすることができ、あるいはMLEますスペースのニーズを忘れないでください
- 初期化時間の最初の行は、入力のサブセットであるかどうかを検討します
データを提供することに
1つの
P
1 1
H
12 9
HPHHPHHPH
PPPHHPPHP
HHPHHHHPP
PHHHHPHHP
HHHPHPHHH
HPHPPPPPP
PPPHHPPPP
HPHPHHHPH
PPHPPPHPH
PHPHPPPHP
HPHHPHHPH
HPPPHHPHH
1
0
25
AC-コード
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int mod = 1e9;
int f[101];
int dp[101][70][70]; // 第 i 行,状态为 j,i-1行状态为 k 时候的最大价值
int state[70];
int num[70]; // 每种状态 1 的个数
int cnt;
int main() {
ios;
int n, m;
while (cin >> n >> m) {
cnt = 0;
memset(dp, 0, sizeof(dp));
for (int i = 0; i < 1 << m; ++i) {
if (!(i & i << 2) && !(i & i << 1))
state[cnt] = i;
else
continue;
int j = 0;
int temp = i;
for (j = 0; temp; ++j)
temp &= (temp - 1); // 去掉最低位的 1
num[cnt++] = j;
}
for (int i = 1; i <= n; ++i) {
string str;
cin >> str;
int sum = 0;
for (int j = 0; j < m; ++j) {
if (str[j] == 'P') // 1 :平原, 0 :山
sum = sum << 1 | 1;
else
sum = sum << 1;
}
f[i] = sum;
}
for (int i = 0; i < cnt; i++) {
if (!(state[i] & f[1])) continue;
dp[1][i][0] = num[i]; // 第 1 行初始化
}
for (int i = 2; i <= n; ++i) { // 第 i 行
for (int j = 0; j < cnt; ++j) { // 枚举当前行状态 j
if ((state[j] & f[i]) == state[j]) {
for (int k = 0; k < cnt; ++k) { // 枚举上一行状态
if ((state[k] & f[i - 1]) == state[k] && !(state[j] & state[k]))
for (int t = 0; t < cnt; ++t) {
if ((state[t] & f[i - 2]) == state[t] && !(state[j] & state[t]) && !(state[k] & state[t]))
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][t] + num[j]);
}
}
}
}
}
int ans = 0;
for (int i = 0; i < cnt; ++i) {
for (int j = 0; j < cnt; ++j) {
ans = max(ans, dp[n][i][j]);
}
}
cout << ans << endl;
}
}