P2704 [NOI2001] 炮兵阵地(状压dp)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2704 [NOI2001] 炮兵阵地(状压dp)相关的知识,希望对你有一定的参考价值。

P2704 [NOI2001] 炮兵阵地(状压dp)

第一在想压一行怎么递推。

结果发现没发递推。因为影响的状态有两行。

没想到01年就有压多行的操作,我老了。

因此自然地就有 d p [ p r e ] [ n o w ] [ i ] dp[pre][now][i] dp[pre][now][i] i i i表示当前第 i i i行, n o w now now当前行的状态, p r e pre pre上一行的状态。

然后递推。左右判断 就用左右位移符号,这里只需要往一个方向移动,因为是相对的。

然后预处理每行的山丘状态记为1.

行与行之间判重就可以了。

code

#include<iostream>
using namespace std;
int n,m,ans,dp[(1<<10)][(1<<10)][3]/*滚动数组*/,a[105],Sum[(1<<10)];
char x;
int getsum(int S)	//当前状态 S 里面包含几个 1

	int tot=0;
	while(S) if(S&1) tot++; S>>=1;
	return tot;

int main()

	cin>>n>>m;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			cin>>x,a[i]<<=1,a[i]+=(x=='H'?1:0);	//转成二进制数
	for(int i=0;i<(1<<m);i++)
		Sum[i]=getsum(i);	//初始化 Sum 数组
	for(int S=0;S<(1<<m);S++)
		if(!(S&a[0] || (S&(S<<1)) || (S&(S<<2))))
			dp[0][S][0]=Sum[S];	//初始化
	for(int L=0;L<(1<<m);L++)
		for(int S=0;S<(1<<m);S++)
			if(!(L&S || L&a[0] || S&a[1] || (L&(L<<1)) || (L&(L<<2)) || (S&(S<<1)) || (S&(S<<2))))	//谜之一长串特判
				dp[L][S][1]=Sum[S]+Sum[L];
	for(int i=2;i<n;i++)
		for(int L=0;L<(1<<m);L++)
		
			if(L&a[i-1] || (L&(L<<1)) || (L&(L<<2))) continue;	//特判
			for(int S=0;S<(1<<m);S++)
			
				if(S&a[i] || L&S || (S&(S<<1)) || (S&(S<<2))) continue;
				for(int FL=0;FL<(1<<m);FL++)
				
					if(FL&L || FL&S || FL&a[i-2] || (FL&(FL<<1)) || (FL&(FL<<2)))	continue;
					dp[L][S][i%3]=max(dp[L][S][i%3],dp[FL][L][(i-1)%3]+Sum[S]);		//滚动数组的实现方法
				
			
		
	for(int L=0;L<(1<<m);L++)
		for(int S=0;S<(1<<m);S++)
			ans=max(ans,dp[L][S][(n-1)%3]);	//结束状态可以是最后一行的任何状态
	cout<<ans;
	return 0;

以上是关于P2704 [NOI2001] 炮兵阵地(状压dp)的主要内容,如果未能解决你的问题,请参考以下文章

状压DP NOI2001 炮兵阵地

洛谷P2704NOI2001炮兵阵地

(状压dp)NOI 2001(POJ 1185) 炮兵阵地

状压DP 洛谷P2704 炮兵阵地

JZYZOJ1390noi2001炮兵阵地 状压DP

NOI2001炮兵阵地