首页 > 代码库 > 洛谷OJ 2051 中国象棋 DP(计数)
洛谷OJ 2051 中国象棋 DP(计数)
https://www.luogu.org/problem/show?pid=2051
题意:n*m棋盘,n,m<=100 问在棋盘上放炮 使得任意两个炮都互补攻击(即同行或者同列最多放两个)的方法数?
定义状态,dp[i][j][k] 已经放了i行 有j列放一个炮,有k列放2个炮 (并不需要准确知道当前棋盘的状态)
状态转移时,按照第i行如何放炮即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=9999973; const int N=1e2+20; int n,m; ll dp[N][N][N];//dp[i][j][k] 已经放了i行 有j列放一个炮,有k列放2个炮 ll C(ll x) { return x*(x-1)/2; } int main() { while(cin>>n>>m) { memset(dp,0,sizeof(dp)); dp[0][0][0]=1; for(int i=0;i<n;i++) { for(int j=0;j<=m;j++) { for(int k=0;k<=m-j;k++) { dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k])%mod;//第i+1行不放 //第i+1行 放一个 if(m-j-k>=1) dp[i+1][j+1][k]=(dp[i+1][j+1][k]+dp[i][j][k]*(m-j-k))%mod;//放在空列上 if(j-1>=0) dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k]*j)%mod;//放在有一个棋子的列上 //第i+1行 放两个 if(m-j-k>=2) dp[i+1][j+2][k]=(dp[i+1][j+2][k]+dp[i][j][k]*C(m-j-k))%mod;//空列 if(m-j-k>=1&&j>=1) dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k]*(m-j-k)*j)%mod;//一个在空列,一个在有一个棋子的列上 if(j-2>=0) dp[i+1][j-2][k+2]=(dp[i+1][j-2][k+2]+dp[i][j][k]*C(j))%mod;//两个都在有一个棋子的列上 } } } ll ans=0; for(int j=0;j<=m;j++) for(int k=0;k<=m-j;k++) ans=(ans+dp[n][j][k])%mod; cout<<ans<<endl; } return 0; }
洛谷OJ 2051 中国象棋 DP(计数)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。