2016-06-01 18:24:32
题目链接: 中国象棋 (Codevs No.2227)
题目大意:
在一个N*M的棋盘上放置中国象棋中的炮,求使的放置的炮不能互相攻击的方案总数MOD奇怪的数
解法:
一看就是动态规划(QAQ一看就不会)
看了看题解理解了一下
DP[i][j][k]表示现在处于i行,其中已有j列是放置了一个炮,有k列是放置了两个炮(那么空的就是M-j-k喽)
这个状态一共可能有6种来源
1.没做改变 直接从上一行推来 DP[i][j][k]+=DP[i-1][j][k]
2.在空列放置了一个 DP[i][j][k]+=DP[i-1][j-1][k]*(M-k-j+1); (后面乘的就是空列的个数)
3.在空列放置了两个并且不重叠 DP[i][j][k]+=DP[i-1][j-2][k]*(M-k-j+2)*(M-k-j+1)/2; (后面乘的是在M-k-j+2个空列中取两个的组合数)
4.在放置了一个的列上再放一个 DP[i][j][k]+=DP[i-1][j+1][k-1]*(j+1); (后面乘的是放了一个的列个数)
5.在放置了一个的不同两列上再各放一个 DP[i][j][k]+=DP[i-1][j+2][k-2]*(j+2)*(j+1)/2; (后面是在j+2个放了一个的列中取两个的组合数)
6.在放置了一个的列和一个空列上各放一个 DP[i][j][k]+=DP[i-1][j][k-1]*(M-k-j+1)*j; (这个好好想想吧,j牵扯到两次改变,领会就好)
1 //中国象棋 (09 安徽) 2 //动态规划 3 #include<stdio.h> 4 #include<algorithm> 5 using namespace std; 6 const int MOD=9999973; 7 const int maxn=110; 8 long long DP[maxn][maxn][maxn]; 9 int N,M; 10 long long ans; 11 int main() 12 { 13 scanf("%d %d",&N,&M); 14 DP[0][0][0]=1; 15 for(int i=1;i<=N;i++) 16 { 17 for(int j=0;j<=M;j++) 18 { 19 for(int k=0;k<=M-j;k++) 20 { 21 DP[i][j][k]+=DP[i-1][j][k]; 22 DP[i][j][k]%=MOD; 23 if(j>=1) 24 { 25 DP[i][j][k]+=DP[i-1][j-1][k]*(M-k-j+1); 26 DP[i][j][k]%=MOD; 27 } 28 if(j>=2) 29 { 30 DP[i][j][k]+=DP[i-1][j-2][k]*(M-k-j+2)*(M-k-j+1)/2; 31 DP[i][j][k]%=MOD; 32 } 33 if(j>=1&&k>=1) 34 { 35 DP[i][j][k]+=DP[i-1][j][k-1]*(M-k-j+1)*j; 36 DP[i][j][k]%=MOD; 37 } 38 if(k>=1) 39 { 40 DP[i][j][k]+=DP[i-1][j+1][k-1]*(j+1); 41 DP[i][j][k]%=MOD; 42 } 43 if(k>=2) 44 { 45 DP[i][j][k]+=DP[i-1][j+2][k-2]*(j+2)*(j+1)/2; 46 DP[i][j][k]%=MOD; 47 } 48 } 49 } 50 } 51 for(int i=0;i<=M;i++) 52 { 53 for(int j=0;j<=M-i;j++) 54 { 55 ans+=DP[N][i][j]; 56 ans%=MOD; 57 } 58 } 59 printf("%lld",ans); 60 }