【poj1185】【NOI2001】炮兵陣地 狀壓dp

又是一道狀壓dp經典題!

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#define M 1<<10
#define N 105
using namespace std;
int dp[N][N][N],mp[N],a[N],b[N],n,m,ToT;
bool judge(int x) {
	bool ret=true; 
	if (x&(x<<1)) ret=false;//相差距離爲1
	if (x&(x<<2)) ret=false;//相差距離爲2
	return ret;
}
int count(int x) {//數有多少個炮兵
	int ret=0;
	for (;x;x>>=1) 
		if (x&1) ret++;
	return ret; 
}
void init() {
	for (int i=0;i<(1<<m);i++) 
		if (judge(i)) a[++ToT]=i,b[ToT]=count(i);
}
bool check(int x,int y) {return (mp[x]&a[y])==0?true:false;}//是否放在了山上
bool check2(int x,int y){return (a[x]&a[y])==0?true:false;}//是否相互打到
int solve() {
	int ret=0;memset(dp,-1,sizeof(dp));
	dp[0][0][0]=1;
	for (int i=1;i<=ToT;i++) {//首先預處理出第一行
		if (check(1,i)) {
			dp[1][i][1]=b[i];
			ret=max(ret,dp[1][i][1]);
		}
	}
	for (int i=2;i<=n;i++) {
		for (int j=1;j<=ToT;j++) {
			if (check(i,j)) {
				for (int k=1;k<=ToT;k++) {
					if (check(i-1,k)&&check2(j,k)) {//前一行
						int cur=0;
						for (int l=1;l<=ToT;l++)//再前一行
							if (check(i-2,l)&&check2(j,l)) 
								cur=max(dp[i-1][k][l],cur);
						dp[i][j][k]=max(dp[i][j][k],cur+b[j]);
						if (i==n) ret=max(dp[i][j][k],ret);							
					}			
				}
				
			}
		}
	}
	return ret;
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++) {
			char ch=getchar();
			for (;!isalpha(ch);ch=getchar());//防止讀入空格
			if (ch=='H') mp[i]|=1<<(m-j);//如果不能放的話就標記
		}
	init();
	printf("%d\n",solve());
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章