[bzoj1801][Ahoi2009]chess 中国象棋

针对一个N行M列的棋盘,求解放置若干个炮(数量为0或更多),使得任意两个炮不能互相攻击的有效放置方案总数。采用动态规划算法进行解答,状态转移过程中考虑了炮放置的数量而非具体位置。

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

来自FallDream的博客,未经允许,请勿转载, 谢谢。


在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.

n,m<=100

 

直接状压dp不可能了

但是发现所有的列只有放了几个会影响答案,它是哪列无所谓,转移都相同。

所以可以用f[i][j][k]表示前i行有j个列没放,k个列放了1个的状态数,转移的时候计算一下这么转移的方案数即可。

#include<iostream>
#include<cstdio>
#define MN 100
#define mod 9999973
#define ll long long
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int f[MN+5][MN+5][MN+5],n,m;
inline void R(int&x,ll y){x=(1LL*x+y)%mod;}
int main()
{
    n=read();m=read();
    f[0][m][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=0;j<=m;++j) 
            for(int k=0;k<=m;++k)
                if(f[i-1][j][k])
                {
                    if(j>0) R(f[i][j-1][k+1],1LL*j*f[i-1][j][k]);
                    if(j>1) R(f[i][j-2][k+2],1LL*j*(j-1)/2*f[i-1][j][k]);
                    if(k>0) R(f[i][j][k-1],1LL*k*f[i-1][j][k]);
                    if(k>1) R(f[i][j][k-2],1LL*k*(k-1)/2*f[i-1][j][k]);
                    if(j&&k)R(f[i][j-1][k],1LL*j*k*f[i-1][j][k]);
                    R(f[i][j][k],f[i-1][j][k]);
                }
    int ans=0;
    for(int j=0;j<=m;++j)
        for(int k=0;k<=m;++k)
            R(ans,f[n][j][k]);
    printf("%d\n",ans);        
    return 0;
}

转载于:https://www.cnblogs.com/FallDream/p/bzoj1801.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值