zoukankan      html  css  js  c++  java
  • luogu2051中国象棋

    题目描述

    这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

    输入输出格式

    输入格式:
    一行包含两个整数N,M,之间由一个空格隔开。

    输出格式:
    总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。

    输入输出样例

    输入样例#1:
    1 3

    输出样例#1:
    7

    说明

    样例说明
    除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。

    数据范围
    100%的数据中N和M均不超过100
    50%的数据中N和M至少有一个数不超过8
    30%的数据中N和M均不超过6

    分析:
    说是一道状压DP,然而根本不用预处理状态
    先分析一下题目:要保证每一行每一列的炮要<=2个(原因很简单,超过两个就肯定会有一对可以进行攻击)
    f[i][j][k] 表示已经放了前i行,其中有j列是只放了1个炮,有k列放了2个炮的方案数,那么0的个数就是m-j-k个
    转移一共有6种状态 (乘法和加法原理):
    中间尽量别%,开long long

    这里写图片描述

    注意:因为在最后统计的时候写错了一点(把i写成j),十连WA 惨痛的教训!!!!!

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define LL long long
    
    using namespace std;
    
    const int mod=9999973;
    int n,m;
    LL f[101][101][101];
    
    void doit()
    {
        int i,j,k,l;
        f[0][0][0]=1;
        for (i=1;i<=n;i++)
        {  //f[i][j][k] 表示已经放了前i行,其中有j列是只放了1个炮,有k列放了2个炮的方案数
            for (j=0;j<=m;j++)
            {
                for (k=0;k<=m-j;k++)  //
                {   //我们在这里简称:原没有炮的列:空列;有一个炮:1列;有两个炮:2列 
                    //不放 
                    f[i][j][k]=f[i][j][k]+f[i-1][j][k];
                    //放一个
                    if (j>=1)  f[i][j][k]=f[i][j][k]+f[i-1][j-1][k]*(m-j-k+1); //放在空列上,可选的位置(m-j-k+1) 
                    if (k>=1)  f[i][j][k]=f[i][j][k]+f[i-1][j+1][k-1]*(j+1); //放在1列上 (j+1)
                     //放两个
                    if (j>=2)  f[i][j][k]=f[i][j][k]+f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2;  //两个都放在空列上 (m-j-k+2)*(m-j-k+1)/2 
                    if (k>=2)  f[i][j][k]=f[i][j][k]+f[i-1][j+2][k-2]*(j+2)*(j+1)/2; //两个放在了1列上 (j+2)*(j+1)/2
                    if (j&&k)  f[i][j][k]=f[i][j][k]+f[i-1][j][k-1]*j*(m-j-k+1); //一个在1列上,一个在空列上 (j)*(m-j-k+1)
                    f[i][j][k]%=mod; 
                }
            }
        }
        LL tot=0;
        for (i=0;i<=m;i++)
        {
            for (j=0;j<=m-i;j++)  
               tot=tot+f[n][i][j];
            tot%=mod;
        }
        printf("%d",tot%mod);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        doit();
        return 0;
    } 
  • 相关阅读:
    [原创软件]友盟自动添加版本工具
    【Python3.6+Django2.0+Xadmin2.0系列教程之三(入门篇-下)】学生信息管理系统
    【Python3.6+Django2.0+Xadmin2.0系列教程之二(入门篇-中)】学生信息管理系统
    [原创软件]PC端与移动端文件信息互通工具
    【Python3.6+Django2.0+Xadmin2.0系列教程之一(入门篇-上)】环境搭建及项目创建
    [原创软件]考勤查询工具
    [原创软件]友盟自定义事件批量上传器
    [原创软件]全线升级管理平台
    三步走起 提升 iOS 审核通过率 下篇
    三步走起 提升 iOS 审核通过率 上篇
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673606.html
Copyright © 2011-2022 走看看