炮(棋盘DP)
Posted Only U - IU
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了炮(棋盘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; }
以上是关于炮(棋盘DP)的主要内容,如果未能解决你的问题,请参考以下文章
Luogu P2051 [AHOI2009]中国象棋(dp)
bzoj1801: [Ahoi2009]chess 中国象棋 [dp]