zoukankan      html  css  js  c++  java
  • BZOJ 1801 chess 中国象棋

    题意:

    在n * m 的棋盘上放"炮",使得任意两个炮都不会互相攻击,求方案数。

    题解:

    既然是求方案数,那么考虑数学方法和递推,这一道题的限制条件比较麻烦,数学方法不合适,考虑递推。

    现在考虑定义状态,很显然一维需要行数,表示考虑了前i行,现在在第i行放棋子,需要明白的是每一行每一列最多放两个炮,那么放棋子是有限制条件的,也就是每一列的已经放了的棋子数目在限制当前的放法,那么我们需要再开三维表示,没放棋子的列数,放一个棋子的列数,放两个棋子的列数,仔细一想没放棋子的列数可以通过后两个计算出来,并且第一维也可以滚动起来。

    那么转移也变得很显然了。

    1.第i行不放棋子。

    2.第i行只放一个棋子 : ①放在没放棋子的那一列 ②放在放了一个棋子的那一列

    3.第i行放两个棋子: ①全都放在没放棋子的列上 ②分别放在没放棋子的列和放了一个棋子的列上 ③全都放在放了一个棋子的列上

    代码:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    #define ll long long
    const int N = 1e2 + 7;
    const int mod = 9999973;
    int n, m;
    ll dp[N][N][N];
    
    int calc (int x) {
    	return x * (x - 1) / 2;
    }
    
    int main () {
    	scanf ("%d%d", &n, &m);
    	dp[0][0][0] = 1;
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 0; j <= m; ++j) {
    			for (int k = 0; k <= m; ++k) {
    				dp[i][j][k] += dp[i - 1][j][k];
    				if (j >= 1) dp[i][j][k] += dp[i - 1][j - 1][k] * (m - j - k + 1);
    				if (j >= 2) dp[i][j][k] += dp[i - 1][j - 2][k] * calc(m - k - j + 2);
    				if (k >= 1 && j <= m - 1) dp[i][j][k] += dp[i - 1][j + 1][k - 1] * (j + 1);
    				if (k >= 2 && j <= m - 2) dp[i][j][k] += dp[i - 1][j + 2][k - 2] * calc(j + 2);
    				if (k >= 1) dp[i][j][k] += dp[i - 1][j][k - 1] * (m - k - j + 1) * j;
    				dp[i][j][k] %= mod;
    			}
    		}
    	}
    	ll ret = 0;
    	for (int j = 0; j <= m; ++j) 
    		for (int k = 0; k <= m; ++k) 
    			ret = (ret + dp[n][j][k]) % mod;
    	cout << ret << endl;
    	return 0;
    }
    

      

  • 相关阅读:
    列表解析、字典解析、集合解析、生成器解析
    匿名函数lambda
    一、软件开发的常识
    Vocabulary Recitation 2020/04/26
    Vocabulary Recitation 2020/04/25
    Vocabulary Recitation 2020/04/24
    数据结构_郝斌_五种常用排序概述
    Vocabulary Recitation 2020/04/23
    Vocabulary Recitation 2020/04/22
    数据结构_郝斌_树与图
  • 原文地址:https://www.cnblogs.com/xgtao/p/5991072.html
Copyright © 2011-2022 走看看