【状压dp】poj1185 || noi2001炮兵阵地

炮兵阵地
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;
}



   
 
全部评论

相关推荐

bg双非本科,方向是嵌入式。这次秋招一共拿到了&nbsp;8&nbsp;个&nbsp;offer,最高年包&nbsp;40w,中间也有一段在海康的实习经历,还有几次国家级竞赛。写这篇不是想证明什么,只是想把自己走过的这条路,尽量讲清楚一点,给同样背景的人一个参考。一、我一开始也很迷茫刚决定走嵌入式的时候,其实并没有一个特别清晰的规划。网上的信息很零散,有人说一定要懂底层,有人说项目更重要,也有人建议直接转方向。很多时候都是在怀疑:1.自己这种背景到底有没有机会2.现在学的东西到底有没有用3.是不是已经开始晚了这些问题,我当时一个都没答案。二、现在回头看,我主要做对了这几件事第一,方向尽早确定,但不把自己锁死。我比较早就确定了嵌入式这个大方向,但具体做哪一块,是在项目、竞赛和实习中慢慢调整的,而不是一开始就给自己下结论。第二,用项目和竞赛去“证明能力”,而不是堆技术名词。我不会刻意追求学得多全面,而是确保自己参与的每个项目,都能讲清楚:我负责了什么、遇到了什么问题、最后是怎么解决的。第三,尽早接触真实的工程环境。在海康实习的那段时间,对我触动挺大的。我开始意识到,企业更看重的是代码结构、逻辑清晰度,以及你能不能把事情说清楚,而不只是会不会某个知识点。第四,把秋招当成一个需要长期迭代的过程。简历不是一次写完的,面试表现也不是一次就到位的。我会在每次面试后复盘哪些问题没答好,再针对性补。三、我踩过的一些坑现在看也挺典型的:1.一开始在底层细节上纠结太久,投入产出比不高2.做过项目,但前期不会总结,导致面试表达吃亏3.早期有点害怕面试,准备不充分就去投这些弯路走过之后,才慢慢找到节奏。四、给和我背景相似的人一点建议如果你也是双非,准备走嵌入式,我觉得有几件事挺重要的:1.不用等“准备得差不多了”再投2.项目一定要能讲清楚,而不是做完就算3.不要只盯着技术,多关注表达和逻辑很多时候,差的不是能力,而是呈现方式。五、写在最后这篇总结不是标准答案,只是我个人的一次复盘。后面我会陆续把自己在嵌入式学习、竞赛、实习和秋招中的一些真实经验拆开来讲,希望能对后来的人有点帮助。如果你正好也在这条路上,希望你能少走一点弯路。
x_y_z1:蹲个后续
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务