[SCOI2005] 互不侵犯
题目
Description
在 N×N 的棋盘里面放 K 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 8 个格子。
Input
只有一行,包含两个数 N,K。
Output
所得的方案数
Sample Input
3 2
Sample Output
16
思路
一道状压$dp$题;
因为要求国王数量,所以要多开一维数组记录国王总数;
用$dp[i][j][k]$表示第$i$行的状态$k$,并且到第$i$行为止一共放了$j$国王;
把不符合的国王状态去掉即可;
状态转移方程就为: $dp[i][j+sum][k]+=dp[i-1][j][l]$
$sum$为当前行的国王数量;
代码
#include<bits/stdc++.h> typedef long long ll; using namespace std; const ll _=10; ll n,m; ll a[_][_],dp[_][_*_][1<<9]; int main() { scanf("%lld%lld",&n,&m); dp[0][0][0]=1; for(ll i=1;i<=n;i++) for(ll k=0;k<=(1<<n)-1;k++) { if(k&(k>>1)) continue;//相邻不能放 ll sum=0; for(ll j=1;j<=n;j++) if(k&(1<<(j-1))) sum++;//记录当前行国王数量 for(ll l=0;l<=(1<<n)-1;l++) { if(k&l||k&(l<<1)||k&(l>>1))//保证两行的国王互不攻击 continue; for(ll j=0;j<=m-sum;j++)//枚举到上一行的所有国王数量 dp[i][j+sum][k]+=dp[i-1][j][l]; } } ll ans=0; for(ll i=0;i<=(1<<n)-1;i++) ans+=dp[n][m][i]; printf("%lld",ans); return 0; }