*点击

[蓝桥杯 2021 省 AB2] 国际象棋

题目

Description

众所周知, “八皇后” 问题是求解在国际象棋棋盘上摆放 8 个皇后,使得两两之间互不攻击的方案数。已经学习了很多算法的小蓝觉得 “八皇后” 问题太简单了,意犹末尽。作为一个国际象棋迷,他想研究在 N×M 的棋盘上,摆放 K 个马,使得两两之间互不攻击有多少种摆放方案。由于方案数可能很大,只需计算答案除以 1000000007 (即 1e9+7) 的余数。

如下图所示,国际象棋中的马摆放在棋盘的方格内,走 “日” 字, 位于 (x,y) 格的马(第 x 行第 y 列)可以攻击 (x+1,y+2),(x+1,y−2),(x−1,y+2),(x−1,y−2),(x+2,y+1),(x+2,y−1),(x−2,y+1),(x−2,y−1) 共 8 个 格子。

 

Input

输入一行包含三个正整数 N,M,K 分别表示棋盘的行数、列数和马的个数。

Output

输出一个整数,表示摆放的方案数除以 1000000007( 即 109+7)的余数。

Sample Input

4 4 3

Sample Output

276

思路

一道状压$dp$题;

[SCOI2005] 互不侵犯差不多,只不过因为马可以攻击到下两行的地方,所以需要多开一维数组存上一行的状态;

用$dp[i][j][x][y]$表示第$i$行的状态$x$,第$i-1$行状态$y$,并且到第$i$行为止一共放了$j$个马;

状态转移方程就为:  $dp[i][j+sum][x][y]+=dp[i-1][j][y][z]$

$sum$为当前行的马的数量,$z$表示上上行的状态;

 


 

代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll mod=1e9+7;
ll n,m,k;
ll a[101][7],dp[101][21][1<<6][1<<6];
int main()
{
    scanf("%lld%lld%lld",&m,&n,&k);
    dp[0][0][0][0]=1;
    for(ll i=1;i<=n;i++)
    for(ll x=0;x<=(1<<m)-1;x++)
    {
        ll sum=0;
        for(ll j=1;j<=m;j++)
        if(x&(1<<(j-1)))
            sum++;//统计当前行马的数量
        for(ll y=0;y<=(1<<m)-1;y++)
        for(ll z=0;z<=(1<<m)-1;z++)
        {
            if(x&(z>>1)||x&(z<<1))//上上行与当前行互不攻击
                continue;
            if(x&(y>>2)||x&(y<<2))//上一行与当前行互不攻击
                continue;
            for(ll j=0;j<=k-sum;j++)//枚举到上一行为止马的总数
                dp[i][j+sum][x][y]=(dp[i][j+sum][x][y]+dp[i-1][j][y][z])%mod;
        }
    }
    ll ans=0;
    for(ll x=0;x<=(1<<m)-1;x++)
    for(ll y=0;y<=(1<<m)-1;y++)
        ans=(ans+dp[n][k][x][y])%mod;
    printf("%lld",ans);
    return 0;
}

 

 

 

 

 

 

posted @ 2024-12-17 22:18  木偶人-怪咖  阅读(4)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录