[POJ 1185--大砲状の圧力空間の前処理DPと最適化]

トピックポータル


説明

コマンド将軍は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;
	}
}


公開された104元の記事 ウォン称賛60 ビュー5851

おすすめ

転載: blog.csdn.net/Q_1849805767/article/details/103590031