题面
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入:只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N
分析
数据规模极小+状态极多+网格题 == 状压dp
套路:有放置的个数限制我们就需要在dp加一维。
dp[i][j][k]表示扫到第i层,本层选择j状态,到目前为止总共用了k个国王的方案数
还是需要预处理第一行。额外的,还需要预处理出每一种状态需用的国王数量(即计算二进制位有多少个1)
#include<bits/stdc++.h> using namespace std; #define N 10 #define M 1<<10 #define ll long long ll dp[N][M][N*N],ok[M],need[M]; ll n,k,mx,ans; int main() { cin>>n>>k; mx=(1<<n)-1; for(int i=0;i<=mx;i++) { int pos=i; while(pos) { if(pos%2)need[i]++; pos>>=1;//计算出每种状态需要多少King } } for(int i=0;i<=mx;i++) if( ((i>>1)&i)==0 ) ok[i]=1; for(int i=0;i<=mx;i++) if( ok[i] & need[i]<=k) dp[1][i][need[i]]=1; for(int i=2;i<=n;i++) for(int j=0;j<=mx;j++) if(ok[j]) for(int s=0;s<=mx;s++) { if(s&j)continue; if((s<<1)&j)continue; if((s>>1)&j)continue; for(int t=k;t>=need[j];t--) dp[i][j][t]+=dp[i-1][s][t-need[j]]; } for(int i=0;i<=mx;i++) ans+=dp[n][i][k]; cout<<ans; }