问 在n*n 的国际象棋棋盘中 能放 k个象的方案数?
国际象棋中 白格 和 黑格 中的象不能互相攻击, 就可以 把这两部分拆开来看,分别统计
由于象是斜着攻击的,我们可以把棋盘旋转45 度,然后对 格子做 水平和竖直方向的交换(不会影响方案数)。
把白格子弄出来就是
*
* * *
* * * * *
* * * * * * *
* * * * * * *
* * * * *
* * *
*
调整之后 :
*
*
* * *
* * *
* * * * *
* * * * *
* * * * * *
* * * * * *
这样看起来图形更优雅
第i 行的格子个数 C【i】
R【i】【j】 表示 前i 行,放置 j 个棋子的方案数。
R【i】【j】 = R【i-1】【j】 + R【i-1】【j-1】*(c【i】 -( j -1))
递推求解
然后在将两部分的情况 组合起来
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <cstring>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <assert.h>
#include <queue>
#define REP(i,n) for(int i=0;i<n;i++)
#define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)
#define ALLL(x) x.begin(),x.end()
#define SORT(x) sort(ALLL(x))
#define CLEAR(x) memset(x,0,sizeof(x))
#define FILLL(x,c) memset(x,c,sizeof(x))
using namespace std;
const double EPS = 1e-8;
#define LL long long
#define pb push_back
int n , k;
int c[10],c2[10];
int c_tot,c_tot2;
void init_c(){
c_tot = c_tot2 = 0;
for(int i=1;i<=n;i+= 2){
if(i==n){
c_tot ++ ;
c[c_tot] = i;
}else{
c_tot++;
c[c_tot] = i;
c_tot++ ;
c[c_tot] = i;
}
}
for(int i=2;i<=n;i+=2){
if(i==n){
c_tot2 ++ ;
c2[c_tot2] = i;
}else{
c_tot2++;
c2[c_tot2] = i;
c_tot2++ ;
c2[c_tot2] = i;
}
}
}
LL R[30][30];
LL R2[30][30];
void solve(){
CLEAR(R);
CLEAR(R2);
R[0][0] =1 ;
for(int i=1;i<=c_tot;i++){
for(int j=0;j<=c[i];j++){
R[i][j] = R[i-1][j] + R[i-1][j-1]*(c[i] - (j-1));
// cout << R[i][j]<<" ";
}
// cout << endl;
}
R2[0][0] =1;
for(int i=1;i<=c_tot2;i++){
for(int j =0;j<=c2[i];j++){
R2[i][j] = R2[i-1][j] + R2[i-1][j-1]*(c2[i] - (j-1));
}
}
LL ans = 0;
for(int i =0;i<=k;i++){
ans += R[c_tot][i] * R2[c_tot2][k-i];
}
cout << ans <<endl;
}
int main(){
while(~scanf("%d%d",&n,&k)){
if(n == 0 && k == 0 )break;
init_c();
solve();
}
return 0;
}