众所周知,“八皇后” 问题是求解在国际象棋棋盘上摆放 88 个皇后,使得两两之间互不攻击的方案数。
已经学习了很多算法的小蓝觉得 “八皇后” 问题太简单了,意犹未尽。作为一个国际象棋迷,他想研究在 N×MN×M 的棋盘上,摆放 KK 个马,使得两两之间互不攻击有多少种摆放方案。
由于方案数可能很大,只需计算答案除以 10000000071000000007 (即 109+7109+7) 的余数。
如下图所示,国际象棋中的马摆放在棋盘的方格内,走 “日” 字,位于 (x,y)(x,y) 格的马(第 xx 行第 yy 列)可以攻击 (x+1,y+2)(x+1,y+2)、(x+1,y−2)(x+1,y−2)、(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)、(x−2,y+1)(x−2,y+1) 和 (x−2,y−1)(x−2,y−1) 共 88 个格子。
输入格式
输入一行包含三个正整数 N,M,KN,M,K,分别表示棋盘的行数、列数和马的个数。
输出格式
输出一个整数,表示摆放的方案数除以 10000000071000000007 (即 109+7109+7) 的余数。
数据范围
对于 5%5% 的评测用例,K=1K=1;
对于另外 10%10% 的评测用例,K=2K=2;
对于另外 10%10% 的评测用例,N=1N=1;
对于另外 20%20% 的评测用例,N,M≤6,K≤5N,M≤6,K≤5;
对于另外 25%25% 的评测用例,N≤3,M≤20,K≤12N≤3,M≤20,K≤12;
对于所有评测用例,1≤N≤6,1≤M≤100,1≤K≤201≤N≤6,1≤M≤100,1≤K≤20。输入样例1:
1 2 1
输出样例1:
2
输入样例2:
4 4 3
输出样例2:
276
输入样例3:
3 20 12
输出样例3:
914051446
求lowbit的函数来自:Acwing--801. 二进制中1的个数(位运算)_with_wine的博客-CSDN博客
这个题类似于 Acwing 292. 炮兵阵地
思路可以看代码里的注释🤗🤗
#include<bits/stdc++.h>
using namespace std;
const int N=1<<6,M=110,T=30,mod=1000000007;
int n,m,k;
long long f[M][N][N][T];//f[i][a][b][t]前i列,第i-1列的状态为a,第i列的状态为b,此时用的马总数为t条件下的方案数
int lowbit(int x)//计算x中有多少个1,带入题目中就是增加了多少个马
{
int ans=0;
while(x)
{
x-=x&(-x);
ans++;
}
return ans;
}
int main()
{
cin>>n>>m>>k;
f[0][0][0][0]=1;//初始化方案数
int maxn=1<<n;
for(int i=1;i<=m;i++)
for(int a=0;a<maxn;a++)//i-2
for(int b=0;b<maxn;b++)//i-1
{
if((a>>2)&b||a&(b>>2))continue;//a,b有冲突的情况(剪枝)
for(int c=0;c<maxn;c++)
{
if((c>>1)&a||c&(a>>1))continue;//c和b冲突
if((c>>2)&b||c&(b>>2))continue;//c和a冲突
int t=lowbit(c);
for(int j=t;j<=k;j++)
f[i][b][c][j]=(f[i][b][c][j]+f[i-1][a][b][j-t])%mod;
}
}
int res=0;
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
res=(res+f[m][i][j][k])%mod;
cout<<res<<endl;
return 0;
}