histcat

histcat

P2704 [NOI2001] 炮兵陣地

題目#

[NOI2001] 炮兵陣地#

司令部的將軍們打算在 $N\times M$ 的網格地圖上部署他們的炮兵部隊。

一個 $N\times M$ 的地圖由 $N$ 行 $M$ 列組成,地圖的每一格可能是山地(用 $\texttt {H}$ 表示),也可能是平原(用 $\texttt {P}$ 表示),如下圖。

在每一格平原地形上最多可以布置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:

image

如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。

圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。

現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。

對於 $100%$ 的數據,$N\le 100$,$M\le 10$,保證字符僅包含 PH

題解#

首先看到數據範圍,直接狀態壓縮 dp

考慮設計狀態

先嘗試f[i][j]表示推到第 i 行,且第 i 行的狀態的二進制為 j 的,能放下的最多的炮兵部隊

嘗試轉移

f [i][j] 要從 f [i-1][~] 轉移過來,但 f [i-1][~] 的狀態包含的集合又不是都能用,所以沒法轉移

考慮加狀態

f[i][j][fl]表示推到第 i 行,且第 i 行的狀態的二進制為 j 的,第 i-1 行的狀態為 fl 的,能放下的最多的炮兵部隊

可以轉移了

實現#

判斷是否能放,二進制和地圖與一下,二進制本身分別和其左移一位、兩位與一下

其餘同理

出現問題#

1. 狀壓 dp 最好下標從 0 開始

2. 學習了滾動數組

代碼#

#include<bits/stdc++.h>

using namespace std;

int read()
{
	int f = 1, x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9')
	{
		if(ch == '-') f = -1;
		ch = getchar();
	}

	while(ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f * x;
}

int n, m;

int Map[110];//如果是1表示山地,0表示平原 

int f[3][1 << 10][1 << 10]; // i,當前狀態,上一行狀態 
int num_of_1[1 << 10];

int getsum(int x)
{
	int ans = 0;
	while(x)
	{
		x &= (x - 1);
		ans++;
	}
	return ans;
}

int main()
{

	for(int i = 0;i < (1 << 10);i++)
	{
		num_of_1[i] = getsum(i);
	}

	n = read(), m = read();
	char ch;
	for(int i = 0;i < n;i++)
	{
		for(int j = 0;j < m;j++)
		{
			cin >> ch;
			if(ch == 'H')
			{
				Map[i] |= (1 << j);
			}
		}
	}

	for(int j = 0;j < (1 << m);j++)
	{
		if(j & (j << 1) || j & (j << 2) || j & Map[0]) continue;
		f[0][j][0] = num_of_1[j];
	}

	for(int j = 0;j < (1 << m);j++)
	{
		for(int fl = 0;fl < (1 << m);fl++)
		{
			if(j & (j << 1) || j & (j << 2) || j & Map[1] || fl & (fl << 1) || fl & (fl << 2) || fl & Map[0] || j & fl || j & Map[1])
				continue;
			f[1][j][fl] = num_of_1[j] + num_of_1[fl];
		}
	}

	for(int i = 2;i < n;i++)
	{
		for(int j = 0;j <= (1 << m) - 1;j++)//當前行 
		{
			if(j & Map[i] || j & (j << 1) || j & (j << 2))
			{
				continue;
			}
		
			for(int fl = 0; fl <= (1 << m) - 1;fl++)//上一行 
			{
				if(fl & Map[i - 1] || fl & (fl << 1) || fl & (fl << 2) || j & fl)
				{
					continue;
				}
			
				for(int fll = 0; fll < (1 << m);fll++)
				{
					if(fll & Map[i - 2] || fll & (fll << 1) || fll & (fll << 2) || j & fll || fl & fll)
					{
						continue;
					}
				
					f[i % 3][j][fl] = max(f[i % 3][j][fl], f[(i - 1) % 3][fl][fll] + num_of_1[j]);
				
				}
			}
		}
	}


	int ans = 0;

	for(int j = 0;j < (1 << m);j++)
	{
		for(int fl = 0;fl < (1 << m);fl++)
		{
			ans = max(ans, f[(n - 1) % 3][j][fl]);
		}
	}

	cout << ans << endl;
	return 0;
}
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。