poj 1185 状压dp经典

显然的我们把放置炮兵部队的位置用1表示,不放的位置用0表示,每一行用一个二进制数就可以表示放置情况。

这些放置要满足如下条件:(n表示行数 m表示列数)

  1. 每一行的炮台之间距离大于2 所有我们要预处理出所有满足1之间的距离大于2的m位的二进制数 即一个二进制数满足(i&(i>>1))!=0 && (i&(i>>2))!=0
  2. 表示当前行状态的二进制数必须和当前行的地形不冲突 即 (a&i)==i a是当前行的地形所得到的二进制数(H表示0 P表示1得到的二进制数) i 是当前行的放置状态
  3. 当前行的状态和前面两行的状态分别做并运算都是0  这一点应该好理解 因为不能冲突
  4. 由1,2点,我可以去掉很多无用的状态 设每 i 行可填的状态的集合为 S_i 事实证明 条件1下Si 的元素不超过70 并且结合条件2会变得更少(不超过20)

我们先把这些状态都记录下来 用数组的下标去标记这些状态 就可以快速的实现转移了     具体看代码

dp[i][j][k] 表示第 i 行 当前行状态为 j 上一行状态为 k 可以得到的方案数

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[102][70][70],n,m,val[70],b[102][70],num[70],tot;
char s[15];
void gethash(){
	tot = 0;
	for(int i = 0; i < (1<<m); i++)//记录满足条件1的状态 
	if((i&(i>>1))==0&&(i&(i>>2))==0)
	val[++tot]=i;
	for(int i = 1; i <= tot; i++){//记录二进制数1的个数 
		int g = val[i],ct = 0;
		while(g){
			g-=g&-g;
			ct++;
		}
		num[i]=ct;
	}
}
int main(){
	
//	for(int i = 1; i <= tot; i++) printf("val[%d]=%d\n",i,val[i]);
	while(~scanf("%d%d",&n,&m)){
		gethash();
		//for(int i = 1; i <= tot; i++) printf("val[%d]=%d num[%d]=%d\n",i,val[i],i,num[i]);
		for(int i = 1; i <= n; i++){
			scanf("%s",s);
			int has = 0;
			for(int j = 0; j < m; j++)//计算地形所表示的状态 
			has=has*2+(s[j]=='P');
			b[i][0]=1;
			for(int j = 1; j <= tot; j++)//根据地形(条件2)和条件1 把状态集合再缩小 
				if((has&val[j])==val[j]) b[i][b[i][0]++]=j; 	
		}
		b[0][0]=2;b[0][1]=0;
		memset(dp,0,sizeof(dp)); 
		int ans=0;
		for(int i = 1; i < b[1][0]; i++) dp[1][i][1]=num[b[1][i]],ans=max(dp[1][i][1],ans);//初始化 
		for(int i = 2; i <= n; i++){
			for(int j = 1; j < b[i][0]; j++){
				for(int k = 1; k < b[i-1][0]; k++){
					if((val[b[i][j]]&val[b[i-1][k]])!=0) continue;//条件3  
					for(int g = 1; g < b[i-2][0]; g++){
						if((val[b[i-1][k]]&val[b[i-2][g]])!=0) continue;//条件3 
						if((val[b[i][j]]&val[b[i-2][g]])!=0) continue;//条件3 
						dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][g]+num[b[i][j]]);
						ans=max(ans,dp[i][j][k]);
					}
				}
			}
		}
		printf("%d\n",ans);
		//for(int i = 1; i <= n; i++) printf("i=%d a[i]=%d\n",i,a[i]);
	}
	return 0;
}
原创文章 85 获赞 103 访问量 2494

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/105693685