[poj1185]炮兵阵地_状压dp

炮兵阵地 poj-1185

    题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数。

    注释:n<=100,m<=10。然后只能在平原的地方建立炮兵。

      想法:第2到状压dp,++。这题显然是很经典的。设状态dp[i][j][k]表示第i行的状态为j,i-1行的状态为k的最多炮兵数。在转移时,枚举所有的合法炮兵排列(此处的合法数目是根据一行全为平原的时候能放置的合法炮兵数目),然后内层循环枚举dp[i-1]的i-1状态,进行特判更新即可。统计答案时,我们只需对于dp[n]的所有可能状态求最大值即可。

    最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int dp[105][65][65];
int cnt=0;
int str[65];
int sum[65];
int map[110];
char s[110][110];
bool check(int x)//判断这个排列是否为普通的合法序列
{
	if(x&(x<<1)) return false;
	if(x&(x<<2)) return false;
	return true;
}
int getSum(int x)//当前状态的炮兵数目
{
	int ans=0;
	while(x>0)
	{
		if(x&1) ans++;
		x>>=1;
	}
	return ans;
}
void before_hand(int mid)//预处理出所有的可能合法炮兵状态,cnt统计状态数
{
	for(int i=0;i<(1<<mid);i++)
	{
		if(check(i))
		{
			str[cnt]=i;//str数组记录状态,dp中的j和k都是str数组的下标
			sum[cnt]=getSum(i);
			cnt++;
		}
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	memset(dp,-1,sizeof dp);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			char a;
			cin >> a;
			if(a==‘H‘) map[i]|=(1<<j);//统计每一行的不合法格子状态
		}
	}
	before_hand(m);//其实可以不传参
	for(int i=0;i<cnt;i++)
	{
		if(!(str[i]&map[0])) dp[0][0][i]=sum[i];//先处理出第一行的情况
	}
	for(int r=1;r<n;r++)//枚举行数
	{
		for(int i=0;i<cnt;i++)//枚举当前行的排列
		{
			if(str[i]&map[r]) continue;
			for(int j=0;j<cnt;j++)//枚举上一行的排列情况
			{
				if(str[i]&str[j]) continue;
				for(int k=0;k<cnt;k++)//枚举i-2行的排列情况
				{
					if(str[i]&str[k]) continue;
					if(dp[r-1][k][j]==-1) continue;
					dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);//更新即可
				}
			}
		}
	}
	int ans=0;//统计答案
	for(int i=0;i<cnt;i++)
	{
		for(int j=0;j<cnt;j++)
		{
			ans=max(ans,dp[n-1][i][j]);
		}
	}
	printf("%d\n",ans);
	return 0;
}

    小结:这道题非常经典,我们有一种用空间换时间的办法就是4维dp。

      错误:卧槽!!一定牢记...判断时用的是运算符&而不是&&!!!

原文地址:https://www.cnblogs.com/ShuraK/p/8566356.html

时间: 2024-07-30 01:45:26

[poj1185]炮兵阵地_状压dp的相关文章

[POJ1185]炮兵阵地(状压DP)

题目链接:http://poj.org/problem?id=1185 这个和之前的不一样,在于某个点影响的范围是两格.那么dp(cur,pre,i)表示第i行状态为cur,i-1行状态为pre时可以有多少种放法.转移的时候枚举ppre,就是i-2行即可.照葫芦画瓢 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7 ┓┏┓┏┓┃ 8 ┛┗┛┗┛┃ 9 ┓┏┓┏┓┃ 10 ┛┗┛┗┛┃ 1

poj1185:炮兵阵地(状压dp)

也算是比较基础的状压dp了,跟做过的第二道比较又稍微复杂了一点 需要记录之前两行的状态.. 统计结果也稍有不同 另外还学习了一个得到一个整数二进制位 1 的个数的位运算方法 详见代码: #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> using namespa

POJ 1185 炮兵阵地(状压DP入门)

http://poj.org/problem?id=1185 状压DP: 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int dp[105][100][100]; 7 int ma[105],st[105]; 8 9 int ok(int x) 10 { 11 return (x&(x<<1))+(x&(x&

POJ 1185 炮兵阵地 (状压DP)

题目链接 题意 : 中文题不详述. 思路 :状压DP,1表示该位置放炮弹,0表示不放.dp[i][j][k],代表第 i 行的状态为k时第i-1行的状态为 j 时放置的最大炮弹数.只是注意判断的时候不要互相攻击到就可以了,还要与地形相适应. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std

poj 1185 炮兵阵地(状压DP)

炮兵阵地 \(solution:\) 这一道题限制条件有点多,我们需要逐个击破: 首先要判断这一格是否为山地,这个可以状态压缩 然后我们的左右一定距离不能有炮兵,这是一个突破口,因为我们看数据发现每行不超过十个格子!这样的话我们完全可以预处理出来每一行的填充方案而且这些方案肯定很少! 某一格的前面两格也不能有炮兵.这个限制最麻烦,他涉及了前两行,我们如果要从第一行开始向下推,那就必须知道前两行的所有情况!但是这些在极小的数据范围面前都可以想办法解决. 这是这道题的三个关键点,然后我们可以想到用前

【POJ】1185 炮兵阵地(状压dp)

题目 传送门:QWQ 分析 看到$ M<=10 $考虑状压. 然后把每行都压一下,那么每个状态相关的就是上一行和上上行的状态. 然后枚举. 然后复杂度最坏是$ O(100 \times 1024^3) $的 仔细分析一下,有很多状态是无用的,但还是被判断了,比如$ 11111 $,显然不能做到不误伤. 那么我们把所有可能的状态拉出来(据说小于70?),即代码中的$ st $数组 然后用$ dp[i][j][k] $ 表示前i行上行状态st[j]本行状态st[k]的最大炮兵数量 最后统计答案时把最

RQNOJ 328 炮兵阵地:状压dp

题目链接:https://www.rqnoj.cn/problem/328 题意: 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队. 一个N*M的地图由N行M列组成(N≤100,M≤10),地图的每一格可能是山地(用'H' 表示),也可能是平原(用'P'表示),如下图. 在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队): 一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:

POJ 1185 炮兵阵地 (状压DP,轮廓线DP)

题意: 给一个n*m的矩阵,每个格子中有'P'或者'H',分别表示平地和高原,平地可以摆放大炮,而大炮的攻击范围在4个方向都是2格(除了自身位置),攻击范围内不能有其他炮,问最多能放多少个炮?(n<=100,m<=10) 思路: 明显需要记录到最顶上的2格,所以一共需要记录2*m个格子有没有放炮,2*m<=20,这个数字还是很大的.但是由于炮的攻击范围比较大,所以能放得下的炮比较少,也就意味着状态比较少,那么只要不用枚举[0,1<<2*m)这么大的范围都是可以解决的.即使n=

poj -1185 炮兵阵地 (经典状压dp)

http://poj.org/problem?id=1185 参考博客:http://poj.org/problem?id=1185 大神博客已经讲的很清楚了,注意存状态的时候是从1开始的,所以初始化的时候也是dp[1][1][state],从0开始的话,状态就是dp[1][0][state]了. dp[i][j][k]表示第i行状态为k第i-1行状态为j时的方案数. dp[i][j][k]=max(dp[i][j][k],dp[i-1][t][j]+num[k]); (num[k]为k状态中1