题目大意
给定一个N*N(n<=10,k<=n*n)大小的棋盘,要求你在棋盘上放置k个国王,使得不会相互攻击,如果棋盘上某个格子放置了一个国王,那么与他相邻的八个格子都是他的攻击范围,问有多少种放置方案
题解
和炮兵阵地差不多,只不过这个题是统计方案,依然是逐行转移,如果某个格子(i,j)放置了国王,那么上一行j,j-1,j+1,这三个格子都是他的攻击范围,因此这三个格子是不能够放国王的,由于我们需要的答案是恰好放置k个国王的方案数,所以方程还需要加一维,记录放置的国王数。先预处理出一行的合法状态(用s数组记录)以及放置(sum数组记录)的国王个数方程表示为:dp[i][a][k]+=dp[i-1][b][k-sum[a]](s[a]&s[b]==0)
代码:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; #define MAXN 11 typedef long long LL; LL dp[MAXN][1<<MAXN][MAXN*10]; int s[1<<MAXN],cnt,sum[1<<MAXN]; int get_sum(int x) { int ret=0; while(x) { ret+=(x&1); x>>=1; } return ret; } void pre_solve(int n) { for(int i=0;i<(1<<n);i++) if(!(i&(i>>1))) { s[cnt]=i; sum[cnt++]=get_sum(i); } } bool check(int a,int b) { if(a&b) return false; if((a>>1)&b) return false; if((a<<1)&b) return false; return true; } int main() { int n,k; while(scanf("%d%d",&n,&k)!=EOF) { memset(dp,0,sizeof(dp)); cnt=0; pre_solve(n); for(int i=0;i<cnt;i++) { dp[1][i][sum[i]]=1; } for(int i=2;i<=n;i++) for(int a=0;a<cnt;a++) for(int b=0;b<cnt;b++) for(int c=sum[a];c<=k;c++) if(check(s[a],s[b])) dp[i][a][c]+=dp[i-1][b][c-sum[a]]; LL ans=0; for(int i=0;i<cnt;i++) ans+=dp[n][i][k]; printf("%I64d ",ans); } return 0; }