uva 861 Little Bishops

问 在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;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值