【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 }
View Code

 


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

 

 
posted @ 2016-04-03 09:13  DMoon  阅读(159)  评论(0编辑  收藏  举报