【状压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;
}



   
 
全部评论

相关推荐

沐芷凌曦:这简历数分别指望了,数分最基本的SQL能力你的经历是完全没办法佐证的,而且简历排版极其混乱。你的奖项为什么要写具体的项目内容;教育经历为什么要写你在什么课学到了什么东西,这些都应该是在专业技能里的;专业技能里你又把项目的内容放了进来,而且专业技能你又在强调ETL,如果说你确定要把ETL作为你专业技能的主体那你的经历为什么不能重点佐证呢;反而项目经历你项目等于你调用PyEcharts做了一个看板,就是最基本的课程设计,也是没办法佐证你对PyEcharts的掌握程度,而且没有说具体用什么技术做了什么东西中间做了什么最终得到了什么结果。
点赞 评论 收藏
分享
从大一开始就开始学习Java,一路走来真的不算容易,每次面试都被压力,不过这次终于达成了自己的一大心愿!时间线和面经:8.17-投递9.1-一面实习+项目拷打看门狗机制讲一下redis加锁解锁的本身操作是什么Lua脚本是干什么的udp和tcp讲一下流量控制讲一下令牌桶算法说一下大端和小端是什么线程和协程有什么区别怎么切换协程切换的时候具体做了什么对于程序来说,你刚才提到的保存和恢复现场,这个现场有哪些信息udp优势现在有一个客户端和服务端,要实现TCP的通信,我们的代码要怎么写服务器怎么感知有新的连接怎么处理多个客户端的请求连接TCP怎么处理粘包和分包现在有两个文件,然后每个文件都有一亿条URL,每个的长度都很长,要怎么快速查找这两个文件共有的URLHashmap底层说一下怎么尽量提升插入和查询的效率如果要查找快,查询快,还有解决非空的问题,怎么做LoadingCache了解吗手撕:堆排序9.4-二面部门的leader,超级压力面拷打实习+项目,被喷完全没东西类的加载到垃圾回收整个底层原理讲一遍类加载谁来执行类加载器是什么东西,和进程的关系Java虚拟机是什么东西,和进程的关系如果我们要执行hello&nbsp;world,那虚拟机干了什么呢谁把字节码翻译成机器码,操作时机是什么Java虚拟机是一个执行单元吗Java虚拟机和操作系统的关系到底什么,假如我是个完全不懂技术的人,举例说明让我明白一个操作系统有两个Java程序的话,有几个虚拟机有没有单独的JVM进程存在启动一个hello&nbsp;world编译的时候,有几个进程JVM什么时候启动比如执行一条Java命令的时候对应一个进程,然后这个JVM虚拟机到底是不是在这个进程里面,还是说要先启动一个JVM虚拟机的进程垃圾回收机制的时机能手动触发垃圾回收吗垃圾回收会抢占业务代码的CPU吗垃圾回收算法简单说说垃圾回收机制的stop&nbsp;the&nbsp;world存在于哪些时机垃圾回收中的计算Region的时候怎么和业务代码并行执行假如只有一个线程,怎么实现并行Java为什么要这么实现Java效率比C++慢很多,那为什么还要这样实现Java虚拟机到底是什么形式存在的说一下Java和C++的区别还有你对Java设计理念的理解无手撕面试结束的时候,我真的汗流浃背了,面试官还和我道歉,说他是故意压力面想看看我的反应的,还对我给予了高度评价:我当面试官这么多年,你是我见过最好的一个9.9-三面临时通知的加面,就问了三十分钟项目9.11-hr面问过往经历,未来计划,想从腾讯实习中得到什么?当场告知leader十分满意我,所以直接ochr面完一分钟官网流程变成录用评估中,30分钟后mt加微信告知offer正在审批9.15-offer这一次腾讯面试体验真的不错,每个面试官能感觉到专业能力很强,反馈很足,比起隔壁某节真是好太多以后就是鹅孝子了
三本咋了:当面试官这么多年你是我见过的最好的一个
你面试被问到过哪些不会的...
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

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