【洛谷P2704】炮兵阵地

题目大意:定义一个炮兵会影响该点所在坐标上下左右两个格子的范围,求一个 N*M 的网格里最多可以放多少个炮兵。

题解:发现这个问题有需要记录两个状态,即:上一层的状态和上两层的状态,若直接进行记录,空间可能会起飞。发现对于一个合法的状态来说,需要满足一行中相邻的两个 1 必须位距离大于等于 2,且满足山地位置不能放炮兵,仅考虑第一个约束条件,先打一个表发现,在 1024 个状态范围内仅有 60 个状态满足第一个条件,因此采用直接记录下满足约束 1 的状态,并通过记录每一行的山地平原情况进行位与即可得到合法状态。时间复杂度为 \(O(100*60*60*60)=O(Accepted)\)

代码如下

#include <bits/stdc++.h>
using namespace std;

char s[20];
int n,m,ans;
int G[101],f[101][61][61],valid[61],tot,num[61];

void read_and_parse(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)if(s[j]=='H')G[i]|=1<<j-1;
	}
	for(int i=0;i<1<<m;i++)
		if(!(i&i<<1)&&!(i&i<<2)){
			valid[++tot]=i;
			int res=i;
			while(res)res-=res&-res,++num[tot];
		}
}

void solve(){
	for(int i=1;i<=tot;i++)
		for(int j=1;j<=tot;j++)
			if(!(valid[i]&valid[j])&&!(valid[i]&G[2])&&!(valid[j]&G[1]))
				f[2][i][j]=num[i]+num[j];
	for(int i=3;i<=n;i++)
		for(int j=1;j<=tot;j++)if(!(valid[j]&G[i]))
			for(int k=1;k<=tot;k++)
				if(!(valid[k]&G[i-1])&&!(valid[k]&valid[j]))
					for(int w=1;w<=tot;w++)
						if(!(valid[w]&G[i-2])&&!(valid[w]&valid[k])&&!(valid[w]&valid[j])){
							f[i][j][k]=max(f[i][j][k],f[i-1][k][w]+num[j]);
							ans=max(ans,f[i][j][k]);
						}
	printf("%d\n",ans);
}

int main(){
	read_and_parse();
	solve();
	return 0;
} 
posted @ 2019-03-19 08:43  shellpicker  阅读(222)  评论(0编辑  收藏  举报