1087. [SCOI2005]互不侵犯King【状压DP】

Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

3 2

Sample Output

16
 
状压DP入门题
f[i][j][k]表示放完i行,第i行状态为j,i行放了k个
 
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define LL long long
 5 using namespace std;
 6 LL state[1026],num[1026];
 7 LL f[10][1024][1024];
 8 LL N,K,m;
 9 void Deal()
10 {
11     for (LL i=0;i<=(1<<N)-1;++i)
12     {
13         LL x=i,pre=-1,cnt=0;;
14         for (LL j=1;j<=9;++j)
15         {
16             if (x&1==pre) break;
17             if (x&1) cnt++;
18             pre=x&1;
19             x>>=1;
20         }
21         if (x==0 && cnt<=K)
22             state[++m]=i,num[m]=cnt;
23     }
24 }
25 
26 bool check(LL x,LL y)
27 {
28     if ((state[x]&state[y])!=0) return false;
29     if (((state[x]<<1)&state[y])!=0) return false;
30     if (((state[y]<<1)&state[x])!=0) return false;
31     return true;
32 }
33 
34 int main()
35 {
36     scanf("%lld%lld",&N,&K);
37     Deal();//预处理每一行的可能情况
38     for (LL i=1;i<=m;++i) f[1][i][num[i]]=1;
39     for (LL i=2;i<=N;++i)
40         for (LL j=1;j<=m;++j)//当前行状态
41             for (LL k=1;k<=m;++k)
42                 for (LL l=num[j];l<=K;++l)
43                     if (check(j,k))
44                         f[i][j][l]+=f[i-1][k][l-num[j]];
45     LL ans=0;
46     for (LL i=1;i<=m;++i)
47         ans+=f[N][i][K];
48     printf("%lld",ans); 
49 }
posted @ 2018-03-31 07:25  Refun  阅读(183)  评论(0编辑  收藏  举报