炮兵阵地
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 17163   Accepted: 6558

Description

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑***域所示: 

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

Input

第一行包含两个由空格分割开的正整数,分别表示N和M; 
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

Output

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output

6

Source



曾经觉得好难的题……正如我国庆节那次做这个题的时候说的其实不是想象中的那么难
第三次做了,高二的时候纠缠的一周(渣渣掩面泪奔),去年国庆的时候是看着高中同学的题解写的(再次鸣谢昊神牛!)今天自己很快就搞出来了有前两次的积累,其实也是跟前两道的铺垫分不开的,熟悉的时候做感觉确实不一样


////--------------------------------------下面进入主题部分------------------------------------------------------------
还是用01表示每行的状态,
由于每一行都与它的前两行有关 f[i][j][k] 表示第i行为第j个状态,第i - 1行为第k个状态时所用的最大炮兵数
所以 f[i][j][p] = max(f[i][j][p],  f[i - 1][p][q] + num[j])
值得注意的是,
(1)符合条件的状态时任意1左右两边两位都不是1,于是判断条件是((i & (i >> 1)) == 0) && ((i & (i >> 2)) == 0)
(2)边界处理的时候要提前处理两行
(3)由于我单独处理前两行是第一行是写的if ((state[i] & a[1]) == 0) f[1][i][0] = num[i]; 在只有一行的时候就要特判了
(4)每一行可能的状态只有60种,问我怎么知道的?在生成可行状态之后输出一下最大个数就好了啊!


///////--------------------------------------下面再说两句废话的分割线----------------------------------------------------------


9点过了才开始做这个题,在实验室的时候连样例都还没过到,回来寝室后休息了一会觉得不做出来简直不安心,于是拿出来一看,简单一改就过了。挺开心的,但同时也让我想了很多。这个题确实是没有想象中的那么难,之前一直感觉恼火其实是自己把自己吓到了,说实话我觉得高中的竞赛对我现在的ACM有利也有弊吧,好处就是那强烈的喜欢,并且已经知道很多东西了,有大致的学习方向,而且早就已经知道这是一个很艰难的路程很残酷的比赛,所以会更努力些;坏处就是基础可能会有点不牢( 现在觉得高中那个“空中楼阁”建的太神奇了,所以寒假在家补打地基……)还有就是在一定情况下定式思维已经养成了,比较难以克服;然后是对有的东西确实是留阴影了吧 ,比如这道题,再比如让我“输方案”,再比如搜索,我很清楚一点都不难,只是自己还是怕,心虚(需要时间,我会一个一个去克服!)
今天先到此为止吧,困死了,代码发上来就睡了,原谅我突然废话如此之多

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const long N = 110, MAX = 70;
long n, m, t;
long a[N];
long state[MAX];
long num[MAX];
long long f[N][MAX][MAX];
inline long max (long a, long b)
{
	return a > b ? a : b;
}
long cala(long x)
{
	long sum = 0;
	while (x > 0)
	{
		if ((x & 1) == 1) sum++;
		x >>= 1;
	}
	return sum;
}
int main()
{
	freopen("poj1185.in", "r", stdin);
	scanf("%d%d\n", &n, &m);
	for (long i = 1; i <= n; i++)
	{
	    char c;
	    a[i] = 0;
		for (long j = 1; j <= m; j++)
		{
			scanf("%c", &c);
			if (c == 'H') a[i] += (1 << (j - 1));
		}
		scanf("\n");
	}


	long r =  (1 << m) - 1;
	t = 0;
	for (long i = 0; i <= r; i++)
	{
		if (((i & (i >> 1)) == 0) && ((i & (i >> 2)) == 0))
		{
			state[++t] = i;
			num[t] = cala(i);
		}
	}
	//cout << t<< endl;

    memset(f, 0 , sizeof(f));
	for (long i = 1;i <= t; i++)
	{
		if ((state[i] & a[1]) == 0)
			f[1][i][0] = num[i];
       // cout<< state[i]<< ' ' << f[1][i][0]<< endl;
	}

	for (long i = 1; i <= t; i++)
	for (long j = 1; j <= t; j++)
	{
		if ((state[j] & a[2]) != 0) continue;
		if ((state[i] & state[j]) != 0) continue;
		f[2][j][i] = max(f[2][j][i], num[j] + f[1][i][0]);
	}

	for (long i = 3; i <= n; i++)
	{
		for (long j = 1; j <= t; j++)
		for (long p = 1; p <= t; p++)
		for (long q = 1; q <= t; q++)
		{
			if ((state[j] & state[p]) != 0) continue;
			if ((state[p] & state[q]) != 0) continue;
			if ((state[j] & state[q]) != 0) continue;
			if ((state[j] & a[i]) != 0) continue;
			f[i][j][p] = max (f[i][j][p], f[i - 1][p][q] + num[j]);
		}
	}

	if (n == 1)
    {
        long re = 0;
        for (long i = 1; i <= t; i++)
        {
            re = max(re, f[1][i][0]);
        }
        cout << re <<endl;
        return 0;
    }
	long re = 0;
	for (long i = 1; i <= t; i++)
	for (long j = 1; j <= t; j++)
	{
		re = max(re, f[n][i][j]);
	}
	cout << re <<endl;

    return 0;
}