炮(棋盘DP)
一直以为自己写的就是状态压缩,结果写完才知道是个棋盘dp
首先看一下题目
嗯,象棋 ,还是只有炮的象棋
对于方案数有几种,我第一个考虑是dfs,但是超时稳稳的,所以果断放弃
然后记得以前有过和这个题差不多的dp题
所以思路开始转向DP
经仔细思考后 将棋盘的状态压为三维
dp[i][k][j];
i:棋盘的第几行 k:前i行有几列放了一个炮棋 j:前i行有几列放了两个炮棋
因为炮会隔棋打,所以一列或者一行最多存在两个炮棋
所以
dp方程有6个元素:
1:不放炮棋,所以方程为 dp[i][k][j]+=dp[i-1][k][j];
2:往一个没有炮棋的列放一个炮棋,方程为dp[i][j][k]+=dp[i-1][k-1][j]*(m-k-j+1);
3:往一个有一个炮棋的列放一个炮棋,方程为dp[i][j][k]+=dp[i-1][k+1][j-1]*(k+1);
4:往一个有一个炮棋的列放一个炮棋同时往一个没有炮棋的列放一个炮棋,方程为dp[i][j][k]+=dp[i-1][k][j-1]*(k)*(m-j-k+1)/2;
5:往一个有一个炮棋的列放一个炮棋同时往一个有一个炮棋的列放一个炮棋,方程为dp[i][k][j]+=(k+2)*(k+1)/2*dp[i-1][k+2][j-2];
6:往一个没有炮棋的列放一个炮棋同时往一个没有炮棋的列放一个炮棋,方程为dp[i][k][j]+=(m-j-k+2)*(m-j-k+1)/2*dp[i-1][k-2][j];
好了,现在可以贴代码了
#include<cstdio> #include<iostream> #define mod 999983 using namespace std; int n,m; long long int dp[101][101][101],ans=0; int main() { scanf("%d%d",&n,&m); dp[0][0][0]=1; for(int i=1;i<=n;i++) { for(int k=0;k<=m;k++) { for(int j=0;j<=m-k;j++) { dp[i][k][j]=dp[i-1][k][j]; if(k) dp[i][k][j]+=(m-k-j+1)*dp[i-1][k-1][j]%mod; if(j&&k<m) dp[i][k][j]+=(k+1)*dp[i-1][k+1][j-1]%mod; if(k>1) dp[i][k][j]+=(m-j-k+2)*(m-j-k+1)/2*dp[i-1][k-2][j]%mod; if(j>1&&k<m-1) dp[i][k][j]+=(k+2)*(k+1)/2*dp[i-1][k+2][j-2]%mod; if(k&&j) dp[i][k][j]+=(m-j-k+1)*(k)*dp[i-1][k][j-1]%mod; dp[i][k][j]%=mod; } } } for(int i=0;i<=m;i++) { for(int j=0;j<=m-i;j++) { ans+=dp[n][i][j]; ans%=mod; } } printf("%lld\n",ans); return 0; }