转载请注明出处: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;
}