uva 861 Little Bishops 组合数学 (布棋)

本文介绍了一种计算在特定大小的黑白相间的棋盘上放置多个象棋中“相”的算法,确保它们不会互相攻击。通过将棋盘进行变形,简化问题为在不同行和列放置棋子的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出n*n大小的棋盘,黑白两色相间,要在其中放m个相,问使之互不攻击的方案种数。


= ∑(白格子放k个,并且黑格子放m-k个的种数)


分别考虑黑白格子,对于棋盘进行变形,使得不能在斜角位置的条件 变为 不能在同行同列。


白格子的变形方法是:不考虑黑格子,将剩下的白格子顺时针旋转45度,然后压缩。(使得图形变为倒置的Ferres图像)。






#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn= 8   ;

int n,m;

int h[2*maxn+3];//转化后每行的棋子数
int N;
int f(int x)
{
    return x%2;
}
ll ans[2][80];
ll dp[2*maxn+3][80];//递推求解,并不是动归
void cal(int k)
{
    memset(dp,0,sizeof dp);
    dp[0][0]=1;//n为1的情况会用到
    dp[1][0]=1;
    dp[1][1]=h[1];//dp[n][x]表示转换后前n行,用了x个棋子。
    for(int i=2;i<=N;i++)
    {
       dp[i][0]=1;
       for(int j=1;j<=i;j++)
       {
           dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(h[i]-(j-1));
       }
    }

    for(int j=0;j<=m;j++)
    {
        ans[k][j]=dp[N][j];
    }

}

void get(int k)
{
    memset(h,0,sizeof h);
    if(n%2==0)N= k?n:n-1;//如果是棋盘奇数行,那么在右上角颜色的方块转化后应该有这么多行。
    else      N= k?n-1:n;
    for1(i,n) for1(j,n)
    {
        if( abs(f(i)-f(j) )==k )//判断该方块的行列数奇偶性是否相等,结果对应了两种颜色
        h[N+1-min(n+1-i,j)]++;//对应到转换后的行,改行数量+1
    }
    cal(k);

/*
    cout<<N<<endl;
    for(int i=1;i<=N;i++)
    {
        cout<<i<<" "<<h[i]<<endl;
    }*/
}
int main()
{
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        memset(ans,0,sizeof ans);
        get(0);//getwhite
        get(1);//getblack

        ll reg=0;
        for(int i=0;i<=m;i++)
        {
           reg+=ans[0][i]*ans[1][m-i];
        }
        printf("%lld\n",reg);

    }

   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值