容斥原理的应用
小象: 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; }