洛谷 P1896 [SCOI2005]互不侵犯
题目描述
在\(N×N\)的棋盘里面放\(K\)个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共\(8\)个格子。
注:数据有加强\((2018/4/25)\)
输入输出格式
输入格式:
只有一行,包含两个数\(N,K ( 1 <=N <=9, 0 <= K <= N * N)\)
输出格式:
所得的方案数
输入输出样例
输入样例#1:
3 2
输出样例#1:
16
思路:见代码注释。
代码:
/*f[i][j][k]表示第i行,状态为j,前面摆了k个国王时方案数*/
#include<cstdio>
#define ll long long
ll n,k,king[513],f[10][513][82],num,state[513],ans;
//state是当前状态,king是当前状态的国王数
int main() {
scanf("%d%d",&n,&k);
int maxn=1<<n;
for(int i=0;i<maxn;++i) { //预处理出所有可能组成的状态
if(!(i&(i<<1))) {
state[++num]=i;
int res=i;
while(res) {
if(res&1) ++king[num]; //记录这个状态下国王的个数
res>>=1;
}
}
}
for(int i=1;i<=num;++i)
if(king[i]<=k) f[1][i][king[i]]=1;
//所有状态下的国王个数不能超过k
for(int i=2;i<=n;++i) { //状态转移,注意判断合法,冲突即可。
for(int j=1;j<=num;++j) {
for(int l=1;l<=num;++l) {
if(state[j]&state[l]) continue;
if(state[j]&(state[l]<<1)) continue;
if((state[j]<<1)&state[l]) continue;
for(int s=1;s<=k;++s) {
if(s+king[j]>k) continue;
f[i][j][king[j]+s]+=f[i-1][l][s];
}
}
}
}
for(int i=1;i<=n;++i)
for(int j=1;j<=num;++j)
ans+=f[i][j][k];
printf("%lld\n",ans);
return 0;
}
孤注一掷,我怎甘落空?!