求n*n的棋盘上放K个象的放法, 象可以对角线相互攻击
解法:把红色方格从棋盘中抽出,再将棋盘和小方格都旋转45°再压缩,由于两种颜色的棋盘互不攻击,印刻可以看成两个棋盘,格子棋盘上变为放只能上下攻击的车的个数(详见黑书p244)。
Sgu 221 Big Bishops
解法同上,只是把数据放大了,超long long ,用java里的BigInteger
.
Sgu 222 Little Rooks
用组合数学或者sug220的方法 可以很快求解,状态压缩则需要
当k>=n时,时间复杂度为O(n*2^n)
当k<n时,时间复杂度为O(n*2^n*2^n),想不到更快的...
.
Sgu 223 Little King
n*n的棋盘上放k个King,King可攻击它周围的8个格子,用二进制表示一行放King的情况,1放,0不放。
比如n=3时,有000、001、010、011、100、101、110、111,8种放法,其中只有第1、2、3、5、6这几种是合法的.首先对于一行求出可行的状态,并同时统计出这个状态放了几个King,用num[j]表示
dp[i][j][k] 表示第i行的状态为j,前i行一共放了k个King的总放法,
用(j&k) == 0 &&(j&(k>>1) == 0 && (j&(k<<1) == 0 表示j状态中位置为1(即这个位置放一个King)的正上方、左上方和右上方都为0,这时则有 dp[i][j][k]+=dp[i-1][t][k-num[j]] 时间复杂度O(n*k*tot*tot) 对于n=10 tot=144,
Sgu 224 Little Queens
求n*n的棋盘上放K个Queens的总放法,Queens可以垂直、水平,对角线相互攻击,详见《位运算应用进阶》那篇文章,直接上代码。
void dfs(int lev,int row,int left,int right,int num){ if(num==k){ ans++; return; } if(lev>n) return; int pos=max&(~(row|left|right));//max=(1<<n)-1; dfs(lev+1,row,left<<1,right>>1,num); while(pos!=0){ int p=(pos&-pos); pos-=p; dfs(lev+1,row+p,(left+p)<<1,(right+p)>>1,num+1); } } ans=0; dfs(1,0,0,0,0);