zoukankan      html  css  js  c++  java
  • 洛谷P2051 中国象棋(dp)

    题目链接:传送门

    题目大意:

      在N行M列的棋盘中放象棋中的“炮”,问要使得“炮”两两互不伤害,有多少种放法。

      1 ≤ n,m ≤ 100,答案对9999973取模。

    思路:

      按行更新答案。每行炮可以放在空列(下称A列)和有一个炮的列(下称B列),从而生成B列和有两个炮的列(C列),所以更新行的时候有这样几种选择:

    ①不放“炮”;

    ②选一个A列放一个“炮”,生成一个B列;

    ③选一个B列放一个“炮”,生成一个C列;

    ④选两个A列放一个“炮”,生成两个B列;

    ⑤选两个B列放一个“炮”,生成两个C列;

    ⑥选一个A列和一个B列各放一个“炮”,生成一个B列和一个C列;(注意在同一行不能放两个棋子在同一列,所以不能看作用一个A列生成一个C列)

    考虑到各行各列的顺序与答案无关:

    状态

      f[i][j][k]:第i行有j个B列和k个C列。

    初始状态:

      f[0][0][0] = 1;

    状态转移方程:

      ①f[i][j][k] = f[i-1][j][k];

      ②f[i][j][k] = f[i-1][j-1][k] ×(i-1行A列个数);

      ③f[i][j][k] = f[i-1][j+1][k-1] ×(i-1行B列个数);

      ④f[i][j][k] = f[i-1][j-2][k] ×(i-1行A列个数选2);

      ⑤f[i][j][k] = f[i-1][j+2][k-2] ×(i-1行B列个数选2);

      ⑥f[i][j][k] = f[i-1][j][k-1] ×(i-1行A列个数)×(i-1行B列个数);

    注意边界和取模即可。

    时间复杂度:O(nm2)

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAX_N = 105;
    const int MOD = 9999973;
    
    ll f[MAX_N][MAX_N][MAX_N];
    
    inline int C(int n)
    {//n选2
        return n*(n-1)/2;
    }
    
    int main()
    {
        int N, M;
        cin >> N >> M;
        f[0][0][0] = 1;
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j <= M; j++) {
                for (int k = 0; k+j <= M; k++) {
                    //放1个
                    if (j-1 >= 0 && (M-(j-1+k)) >= 1)
                        f[i][j][k] = (f[i][j][k] + f[i-1][j-1][k] * (M-(j-1+k))) % MOD;
                    if (j+1 <= M && k >= 1)
                        f[i][j][k] = (f[i][j][k] + f[i-1][j+1][k-1] * (j+1)) % MOD;
                    //放两个
                    if (j-2 >= 0 && (M-(j-2+k)) >= 2)
                        f[i][j][k] = (f[i][j][k] + f[i-1][j-2][k] * C(M-(j-2+k))) % MOD;
                    if (k >= 1 && (M-(j+k-1)) >= 1 && j >= 1)
                        f[i][j][k] = (f[i][j][k] + f[i-1][j][k-1] * (M-(j+k-1)) * j) % MOD;
                    if (k >= 2)
                        f[i][j][k] = (f[i][j][k] + f[i-1][j+2][k-2] * C(j+2)) % MOD;
                    //不放
                    f[i][j][k] = (f[i][j][k] + f[i-1][j][k]) % MOD;
                }
            }
        }
        ll ans = 0;
        for (int j = 0; j <= M; j++)
            for (int k = 0; k+j <= M; k++)
                ans = (ans + f[N][j][k]) % MOD;
        cout << ans << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    一步步构建大型网站架构
    程序员技术练级攻略
    再谈“我是怎么招聘程序员的”
    os.path.basename()
    用pymysql实现的注册登录公告练习
    缓冲(cache)和缓存(buffer)
    数据库视图,触发器,事务,存储过程,函数,备份与恢复
    mysql用户管理和pymysql
    mysql重点,表查询操作和多表查询
    数据库的约束语句和表之间的关系
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9840639.html
Copyright © 2011-2022 走看看