【bzoj1087】互不侵犯King
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
Solution
我们很容易的联想到状态压缩动态规划
f[i][j][k][S]表示当前做到(i,j)这个格子共放了k个国王红色部分状态为S的方案数
然后只要枚举当前格子放不放的问题了
红色部分使用状态压缩,而红色部分之前的东西已经不影响答案了
当然可以使用滚动数组
#include<stdio.h> #include<stdlib.h> #include<iostream> #include<string> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<map> #include<vector> #include<set> #define il inline #define re register using namespace std; typedef long long ll; int s=0,t=1,n,m; ll f[2][101][1111],ans=0; il bool chk(int j,int S){ if(j==n) return (S&1)==0&&(S&2)==0&&(S&(1<<n))==0; else if(j==1) return (S&2)==0&&(S&4)==0; return (S&1)==0&&(S&2)==0&&(S&(1<<n))==0&&(S&4)==0; } int main(){ scanf("%d%d",&n,&m); if(n==1){ cout<<"1";exit(0); } if(n==2){ if(m==0) cout<<"1"; else if(m==1) cout<<"4"; else cout<<"0"; exit(0); } f[0][0][0]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ memset(f[t],false,sizeof(f[t])); for(int S=0;S<(1<<n+1);S++){ for(int l=0;l<=m;l++){ if(chk(j,S)) f[t][l+1][(S>>1)|(1<<n)]+=f[s][l][S]; f[t][l][S>>1]+=f[s][l][S]; } } swap(s,t); } } for(int S=0;S<(1<<n+1);S++) ans+=f[s][m][S]; cout<<ans; return 0; }
蜉蝣渴望着飞翔,尽管黄昏将至