poj1185 炮兵阵地 状态压缩dp

    本题的行和列的范围相差很多,因此很容易想到要用状态压缩。对于(i,j)位置,影响它能否放炮兵的因素有两个:1.是否是平地 2.(i-1,j)或(i-2,j)处是否放有炮兵。至于与它同行的就不用考虑了,因为在设计算法是可以很容易的避免同行的相互攻击。所以我们必须要记录i-1行和i-2行的放置炮兵的情况,首先很容易想到把第i-1行和i-2行分别按二进制位压缩,但很快就把这种想法给否定了,因为这样做的话所占空间为 n*1024^2(n<=150),这个数字相当大了。再仔细思考后发现(i-1,j),(i-2,j)这两个位置的炮兵只有三种情况,要么都没放,要么放了一个,所以就想着用三进制位压缩了,0,1,2分别表示着三种情况。然后程序实现就比较简单了,下面贴代码。奋斗

//g++提交 
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[150][60000];
char map[150][12];
//power数组依次存储3^0,3^1,…… 
int power[10]={1,3,9,27,81,243,729,2187,6561,19683};
int n,m;

//获取第pos位上的数字 
int getbit(int i,int pos)
{
	if(pos==0)
		return i%3;
	if(pos>=m)
		return 0;
	if(i>=power[pos])
		return (i/power[pos])%3;
	return 0;
}

//x,y为横纵坐标,cur为上两行的状态,next为下一状态,cnt记录第x行已放置的炮兵 
void dfs(int x,int y,int cur,int next,int cnt)
{
	if(y==0)//刚进入当前行 
	{
		if(dp[x][cur]!=-1)
			return;
		dp[x][cur]=0;
	}
	if(y>=m)//已到行尾 
	{
		if(x<n-1)//转到下一行 
		{
			dfs(x+1,0,next,0,0);
			dp[x][cur]=max(dp[x][cur],cnt+dp[x+1][next]);
		}
		else//已到最后一行 
			dp[x][cur]=max(dp[x][cur],cnt);
		return;
	}
	
	//下面主要注意状态的转移部分了,一定要细心 
	int i=getbit(cur,y);
	if(i==0&&map[x][y]=='P')//(x,y)处可以放置炮兵 
	{
		int j=2*power[y],k;
		k=getbit(cur,y+1);
		
		if(k==2)
			j+=power[y+1];
		k=getbit(cur,y+2);
		if(k==2)
			j+=power[y+2];
			
		dfs(x,y+3,cur,next+j,cnt+1);
		dfs(x,y+1,cur,next,cnt);
		return;
	}
	//不能放置炮兵 
	if(i==2)
		dfs(x,y+1,cur,next+power[y],cnt);
	else
		dfs(x,y+1,cur,next,cnt);
}


int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=0;i<n;i++)
			scanf("%s",map[i]);
		memset(dp,-1,sizeof(dp));
		dfs(0,0,0,0,0);
		printf("%d\n",dp[0][0]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值