POJ1185:状态压缩dp

POJ1185

题意

  • 只有p才可以部署部队,攻击范围是四周两格。求最多能够部署的部队个数。

题解

  • dp[i][j][k]表示第i行的状态为j,上一行的状态为k的方案数。
  • 从上到下枚举每一行,进行状态压缩。判断相连三个1的个数是否≤1。
  • 实际上每一行满足条件的状态数很少,所以可以预处理,只有60种状态。
  • 判断这一行与上一行和上上一行是否冲突。如果状态i和j满足i & j = 1,就冲突。
  • 因为第一行上面没有,所以特殊判断。

代码

	#include <iostream>
	#include <cstdio>
	#include <algorithm>
	#include <cstring>
	#include <cmath>
	#include <vector>
	using namespace std;
	int const N = 100 + 5;
	int const MAX = 65;  //战火会影响两个格子,经过下面的函数Init()计算有60种状态
	int mp[N];
	int n,m,state[MAX],cnt,sum[MAX];
	int dp[N][MAX][MAX];
	int lowbit(int x){return x&-x;}
	int getsum(int x){    //得到x的二进制1的个数
		int num = 0;
		while(x){
			num++;
			x -= lowbit(x);     //lowbit函数可用来求解二进制1的个数
		}
		return num;
	}
	void Init(){	
		cnt = 0;
		for(int i=0;i<(1<<m);i++){   
			if((i&(i<<1)) || (i&(i<<2)))	continue; 
			state[++cnt] = i;   //记录每行可行的状态
			sum[cnt] = getsum(i);
		}
	}
	int solve(){
		memset(dp,-1,sizeof(dp));
		for(int i=1;i<=cnt;i++){    
			if(!(state[i] & mp[1]))   //枚举第i行的状态
				for(int j=1;j<=cnt;j++)   //第0行的状态不用判断
					dp[1][i][j] = sum[i];  
		}
		int ans = 0;
		for(int r=2;r<=n;r++){ 
			for(int i=1;i<=cnt;i++){  //枚举第i行
				if(mp[r] & state[i])	continue;  //状态与第i行出图
				for(int j=1;j<=cnt;j++){  //枚举第i-1行				
					if(state[i] & state[j])		continue;   //第i行与第i-1行冲突
					for(int k=1;k<=cnt;k++){   //枚举第i-2行
						if(r != 2 && (state[i] & state[k] || state[j] & state[k])) 	continue;  //第i行与第i-2行冲突
						if(dp[r-1][j][k] == -1)		continue;
						dp[r][i][j] = max(dp[r][i][j],dp[r-1][j][k] + sum[i]);
					}
				}
			}
		}
		for(int i=1;i<=cnt;i++){
			for(int j=1;j<=cnt;j++)
				ans = max(ans,dp[n][i][j]);
		}
		return ans;
	}
	int main(){
		while(~scanf("%d%d",&n,&m)){
			memset(mp,0,sizeof(mp));
			for(int i=1;i<=n;i++){
				for(int j=1;j<=m;j++){
					char t;	scanf(" %c",&t);
					if(t == 'H')	mp[i] = mp[i] | (1<<(m-j));
				}
			}
			Init();
			printf("%d\n",solve());
		}
		return 0;
	}

 

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/89061610