HDU 4529 郑厂长系列故事——N骑士问题(dp,状态压缩)

转载请注明出处:http://blog.csdn.net/u010734277


这道题相当于是poj的炮兵阵地问题的变形。基本模仿炮兵阵地问题就做出来了。

将棋盘用二进制形式保存在数组中,有皇后的地方保存为1,其余为0。

刚开始做的时候一直是第一组数据正确的,第二组数据差了几十,然后以为是哪里没有限制好。后来只测试第二组数据的时候竟然是对的。感觉到可能是哪里数组没有初始化。后来把保存棋盘的数组初始化了就对了。也给了以后做题的一个小经验,测试数据的时候,刚开始最好把样例一组一组的测试,然后再合一起测试。这样就可以避免忘记初始化的问题。

状态转移方程:dp(r,k,j,l)=SUM{dp(r-1,m,k,l-cnt( j ) ) }其中r表示当前行数,k表示r-1行的状态,j表示r行的状态,l表示到第r行为止已经放上去的骑士的数量,m为r-2行所有可行的状态值。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int chessboard[9];
int dp[9][1<<8][1<<8][11];//ÐÐÊý£¬i-1ÐÐ״̬,iÐÐ״̬,iÐÐΪֹ×ÜÆå×ÓÊý 
int T,N;

char getmap(){
	char t;
	cin>>t;
	while(t!='.'&&t!='*'){
		cin>>t;
	}
	return t;
}

int CNTkn(int i){
	int sum=0;
	while(i){
		if(i&1)sum++;
		i>>=1;
	}
	return sum;
}


int main(){
	freopen("data.txt","r",stdin);
	scanf("%d",&T);
	while(T--){
		scanf("%d",&N);
		memset(chessboard,0,sizeof(chessboard));
		for(int i=0;i<8;++i){
			for(int t=0;t<8;++t){
				char a=getmap();
				if(a=='*')chessboard[i]+=(1<<t);
			}
		}
		memset(dp,0,sizeof(dp));
		for(int i=0;i<(1<<8);++i){
			int tmp=CNTkn(i);
			if(tmp>N)continue;//add
			if(i&chessboard[0])continue;
			dp[0][0][i][tmp]=1;
		}
		for(int r=1;r<8;++r){
			for(int i=0;i<(1<<8);++i){//µÚrÐÐ״̬Ϊi 
				if(i&chessboard[r])continue;
				if(CNTkn(i)>N)continue;//add
				for(int t=0;t<(1<<8);++t){//r-1ÐÐ״̬Ϊt 
					if(i&(t<<2)||i&(t>>2))continue;
					if(CNTkn(i)+CNTkn(t)>N)continue;//add
					for(int k=0;k<(1<<8);++k){
						if(i&(k<<1)||i&(k>>1))continue;
						if(k&(t<<2)||k&(t>>2))continue;//add
						if(CNTkn(i)+CNTkn(t)+CNTkn(k)>N)continue;//add
						for(int l=0;l<=N;++l){//µ½µÚiÐÐ×ÜÆå×ÓÊýΪl 
							int cntr_1=l-CNTkn(i);
						//	if(dp[r-1][k][t][cntr_1]==0)continue;//add
							if(cntr_1<0)continue;
							dp[r][t][i][l]+=dp[r-1][k][t][cntr_1];
						}
					}//for k
				}//for t
			}//for i
		}//for r
		int ans=0;
		for(int i=0;i<(1<<8);++i){
			for(int t=0;t<(1<<8);++t){
				ans+=dp[7][i][t][N];
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值