【题目描述】
在一个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); 最终可推得状态转移方程。 */