【BZOJ1087】 [SCOI2005]互不侵犯King 状压DP
经典状压DP.
f[i][j][k]=sum(f[i-1][j-cnt[k]][k]); cnt[i]放置情况为i时的国王数量
前I行放置情况为k时国王数量为J
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 #define N 1<<9 5 long long ans; 6 int n,m; 7 int ok_1[N],cnt[N]; 8 int ok_2[N][N]; 9 long long dp[10][9*9+10][N]; 10 void init() 11 { 12 int sum; 13 for (int i=0;i<(1<<n);i++) 14 { 15 if ((i&(i<<1))==0 && (i&(i>>1))==0) 16 { 17 sum=0; 18 for (int j=i;j;j>>=1) sum+=(j&1); 19 cnt[i]=sum; ok_1[i]=1; 20 } 21 for (int i=0;i<(1<<n);i++) 22 if (ok_1[i]) 23 for (int j=0;j<(1<<n);j++) 24 if (ok_1[j]) 25 if ((i&j)==0 && (i&(j>>1))==0 && (i&(j<<1))==0) 26 ok_2[i][j]=1; 27 } 28 } 29 int main() 30 { 31 scanf("%d%d",&n,&m); 32 init(); 33 for (int i=0;i<(1<<n);i++) if (ok_1[i]) dp[1][cnt[i]][i]=1; 34 for (int i=2;i<=n;i++) 35 for (int j=0;j<(1<<n);j++) 36 if (ok_1[j]) 37 for (int k=0;k<(1<<n);k++) 38 if (ok_1[k]) 39 if (ok_2[j][k]) 40 for (int l=cnt[k];l+cnt[j]<=m;l++) 41 dp[i][l+cnt[j]][j]+=dp[i-1][l][k]; 42 for (int i=0;i<(1<<n);i++) 43 ans+=dp[n][m][i]; 44 printf("%lld\n",ans); 45 return 0; 46 }
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
HINT
Source
—Anime Otaku Save The World.