题目地址


易错点:

  • 状压DP无论是在初始化还是转移中,都必须分清楚状态序号和状态.
  • 从初值到第一个转移到的状态和结果值的确定都必须严格保证其正确性.

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=210;
bool isAttackAlly(int x){
	if((x&(x<<1))||(x&(x<<2)))return 1;
	return 0;
}
int countSoldier(int x){
	int cnt=0;
	while(x){
		cnt++;
		x=x&(x-1);
	}
	return cnt;
}
int m;
int cur[MAXN],soldierCnt[MAXN],top;
void init(){
	for(int i=0;i<(1<<m);i++){
		if(!isAttackAlly(i)){
			cur[++top]=i;
			soldierCnt[top]=countSoldier(i);
		}
	}
}
int hills[MAXN];
bool isInHill(int x,int status){
	return status&hills[x];
}
bool isCompatible(int a,int b,int c){
	if((a&b)||(a&c)||(b&c))return 0;
	return 1;
}
int f[MAXN][80][80];
char a[110][11];
int main(){
	int n;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		char tmp;
		for(int j=1;j<=m;j++){
			cin>>tmp;
			if(tmp=='H'){
				hills[i]|=(1<<(m-j));
			}
		}
	}
	init();
	for(int i=1;i<=top;i++){
		int nowValue=cur[i];
		if(!isInHill(1,nowValue)){
			f[1][1][i]=soldierCnt[i];
		}
	}
	for(int x=2;x<=n;x++){
		for(int i=1;i<=top;i++){//first row
			int nowValue1=cur[i];
			if(isInHill(x-2,nowValue1))continue;
			for(int j=1;j<=top;j++){//second row
				int nowValue2=cur[j];
				if(isInHill(x-1,nowValue2))continue;
				for(int k=1;k<=top;k++){//third row
					int nowValue3=cur[k];
					if(isInHill(x,nowValue3))continue;
					if(isCompatible(nowValue1,nowValue2,nowValue3)){
						f[x][j][k]=max(f[x][j][k],f[x-1][i][j]+soldierCnt[k]);
					}
				}
			}
		}
	}
	int ans=-1;
	for(int i=1;i<=top;i++){
		for(int j=1;j<=top;j++){
			ans=max(ans,f[n][i][j]);
		}
	}
	printf("%d\n",ans);
	return 0;
}