中国象棋

【题目描述】

在一个N*M的棋盘上,放置若干个炮(可以为0),使得没有一个炮可以攻击到另一个炮,询问有多少种放置方法。

【输入描述】

输入两个整数N、M。

【输出描述】

输出一个整数,表示方案数模9999973的结果。

【样例输入】

1 3

【样例输出】

7

【数据范围及提示】

样例中,除了3个格子里都放置了炮以外,其它方案都是可行的,共有2*2*2-1=7种方案。

对于30%的数据,N、M均不大于6;

对于50%的数据,N、M中至少有一个数不大于8;

对于100%的数据,N、M均不大于100。

源代码:

#include<cstdio>
#define INF 9999973
int m,n;
long long ans,f[101][101][101];
long long C(long long t) //组合。
{
    return t*(t-1)/2;
}
int main()
{
    scanf("%d%d",&n,&m);
    f[0][0][0]=1;
    for (int a=1;a<=n;a++)
      for (int b=0;b<=m;b++)
        for (int c=0;c<=m-b;c++)
        {
            f[a][b][c]=f[a-1][b][c];
            if (b)
              f[a][b][c]+=f[a-1][b-1][c]*(m-b-c+1);
            if (c&&b<m)
              f[a][b][c]+=f[a-1][b+1][c-1]*(b+1);
            if (b>1)
              f[a][b][c]+=f[a-1][b-2][c]*C(m-b-c+2);
            if (b&&c)
              f[a][b][c]+=f[a-1][b][c-1]*(m-b-c+1)*b;
            if (c>1&&b<m-1)
              f[a][b][c]+=f[a-1][b+2][c-2]*C(b+2);
            if (f[a][b][c]>=INF)
              f[a][b][c]%=INF;
        }
    for (int a=0;a<=m;a++)
      for (int b=0;b<=m-a;b++)
        ans+=f[n][a][b];
    if (ans>=INF)
      ans%=INF;
    printf("%lld",ans);
    return 0;
}

/*
    上帝一般的动态规划。
    设f[k][i][j]为前k行有i列放置1个炮,有j列放置2个炮的方案数。
    那么有如下选择:
        (1)当前行不放置炮,方案数为:f[k-1][i][j];
        (2)在没有炮的列中放置炮,方案数为:f[k-1][i-1][j]*(n-i-j+1);
        (3)在有1个炮的列中放置炮,方案数为:f[k-1][i+1][j-1]*(i+1);
        (4)在没有炮的两列中放置炮,方案数为:f[k-1][i-2][j]*C(n-i-j+2,2);
        (5)在没有炮和有炮的两列中放置炮,方案数为:f[k-1][i][j-1]*(n-i-j+1)*i;
        (6)在有1个炮的两列中放置炮,方案数为:f[k-1][i+2][j-2]*C(i+2,2);
    最终可推得状态转移方程。
*/
原文地址:https://www.cnblogs.com/Ackermann/p/5903407.html