国际象棋


容斥原理的应用
小象: UVA 861
在国际象棋的规定中,象只能从他所在的位置走对角线,如果两只象处于同一斜线上,他们将攻击对方,
现给定2个数字n和k,在n*n的棋盘放k个不互相攻击放入小象有多少种放法? (1=<n<=8)(1=<k<=65)
将棋盘的黑格抽出,剩下的白格子旋转45度,压缩,使得所有位于对角线上的棋子位于一行 ,称之为白棋盘
R_w; 黑棋盘同样处理 R_b
如果在白格子里放i个棋子,在黑格子里放(k-i)个棋子,则由乘法定理:
R=R_w(i)*R_b(k-i)
R[i][j] 代表前i行共放了j个棋子的方法数
对于第j行,分2种情况,放与不放
不放: R[i-1][j]种方法
放: R[i-1][j-1]*(C[i]-(j-1)) 种。(C[i]-(j-1) C[i]代表第i行的棋子数,因为不能同列,不能放在前
j-1个棋子所在的列)

#include<iostream>
#include<algorithm>
using namespace std;
const int N=8;
int w[N+1],b[N+1],R_w[N+1][65],R_b[N+1][65];
void init_chessboard(int n){   //初始化黑白棋盘
    memset(w,0,sizeof(w));
    memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if((i+j)&1)   w[(i+j)>>1]++;
            else
                b[(i+j)>>1]++;
        }
    }
}
//递推公式求解: C代表每行的棋盘数目
void Bishops(int n,int k,int C[N+1],int R[N+1][65]){
    for(int i=0;i<=n;i++)
        R[i][0]=1;
    for(int i=1;i<=k;i++)
        R[0][i]=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=C[i];j++){
            R[i][j]=R[i-1][j]+R[i-1][j-1]*(C[i]-(j-1));
        }
    }
}
int main(){
    int n,k;
    while(cin>>n>>k){
        if(n==0&&k==0)   break;
        init_chessboard(n);
        sort(b+1,b+1+n);
        sort(w+1,w+n);  //w比b少一行
        Bishops(n,k,b,R_b);
        Bishops(n,k,w,R_w);
        int ans=0;
        for(int j=0;j<=k;j++)
            ans+=R_b[n][j]*R_w[n-1][k-j];   //拆分之后一个n行,一个n-1行
      cout<<ans<<endl;
    }
    return 0;
}



原文地址:https://www.cnblogs.com/wintersong/p/4945748.html