POJ --1185--炮兵阵地--状态DP

貌似高中的时候就见过的这题,思路全在代码注释里了

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 120
using namespace std;
int bmp[maxn];		//用二进制表示后,压缩存储地图的每一行 
int n,m;        
int statu[maxn],sc;	//保存一行内长度为 m 的满足互不攻击的排兵状态 ,预先处理,好思想 
int dp[maxn][maxn][maxn];   // //dp[i][j][k]  表示第 i 行状态为 j ,第 i-1 行状态为 k 时的最大排兵数量  
int num[maxn];		//num[i] 表示status[i] 而二进制里面 1 的数量 


void init()
{
	char str[maxn];
	int c,res,u,v;
	cin>>n>>m;
	//读入地图并压缩 
	for(int i=1;i<=n;i++)
	{
		cin>>str;
		res=0;
		for(int j=0;j<m;j++)
		{
			if(str[j]=='P')
			{
				res=res|(1<<(m-1-j));
			}
		}
		bmp[i]=res;
	}
	//预先求出满足条件的状态 
	sc=0;u=1<<m;
	for(int i=0;i<u;i++)
	{
		if((i&(i<<1))==0&&(i&(i<<2))==0)
		{
			statu[sc]=i;
			c=0;
			v=i;
			while(v)
			{
				c+=v%2;
				v/=2;
			}
			num[sc++]=c;
		}
	}
}
void op2(int u)  //输出 u 的二进制表示  ,调试用函数 
{
	if(u==0)return;
	op2(u/2);
	printf("%d",u%2);
}
void check() //检查状态压缩正确与否,调试用 
{
	for(int i=1;i<=n;i++)
	{
		printf("%2d ",bmp[i]);
		op2(bmp[i]);
		cout<<endl;
	}
	cout<<"-------------\n";
	for(int i=0;i<sc;i++)
	{
		op2(statu[i]);
		printf("  %d\n",num[i]);
	}
}
void solve()
{ 
//	check();   此行代码调试用 
	memset(dp,0,sizeof(dp)); //dp[i][j][k]  表示第 i 行状态为 j ,第 i-1 行状态为 k 时的最大排兵数量  
	for(int i=0;i<sc;i++)		//初始化第一行 
	{
		if((statu[i]&bmp[1])!=statu[i])continue;
		for(int j=0;j<sc;j++)
		{
			dp[1][i][j]=num[i];
		}
	}
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<sc;j++)	//枚举第 i 行的状态 
		{
			if((bmp[i]&statu[j])!=statu[j])continue;	//判断状态 j 能够放在第 i 行的地形上 
			for(int k=0;k<sc;k++)	//枚举第 i-1 行的状态
			{
				if(statu[j]&statu[k])continue; 	//判断第 i 行和第 i-1 行是否冲突
				for(int h=0;h<sc;h++)		//枚举第 i-2 行状态 
				{
					if((statu[j]&statu[h])||(statu[k]&statu[h]))continue; //判断第 i 行和第 i-2 行是否冲突,第 i-1行和第 i-2 行是否冲突,貌似这里不需要判断,因为如果i-1 行和 i-2行冲突的话,答案就是0 了,无所谓的. 
					dp[i][j][k]=max(dp[i-1][k][h],dp[i][j][k]); 
				} 
				dp[i][j][k]+=num[j];
			} 
		} 
	}
	int ans=0;
	//欢快的找答案 
	for(int i=0;i<sc;i++)
	{
		for(int j=0;j<sc;j++)
		{
			if(statu[i]&statu[j])continue;
			ans=max(ans,dp[n][i][j]);
		}
	}
	printf("%d\n",ans);  //你懂的 
}

int main()
{
	freopen("1185.txt","r",stdin);
	init();
	solve();
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值