BZOJ-1087: [SCOI2005]互不侵犯King (状压DP)

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4593  Solved: 2662
[Submit][Status][Discuss]

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

这不是跟炮兵阵地一样一样的题嘛QAQ 把每一行可行的情况先预处理出来,再把行之间可行的情况预处理出来,最后DP求和即可qwq 注意!!! (i&(1<<1))==0 最外面的括号一定一定一定要打!!!!已经两题因为这个错找半天了 _(:зゝ∠)_

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 typedef long long LL;
 4 LL n,m,f[15][105][1<<11],num[512],ans;
 5 bool b[512],a[512][512];
 6 void pre(){
 7     LL i,j,s;
 8     for (i=0;i<(1<<n);i++)
 9         if ((i&(i<<1))==0){
10             s=0;
11             for (j=i;j;j>>=1) s+=j&1;
12             num[i]=s,b[i]=true;
13         }
14     for (i=0;i<(1<<n);i++)
15         if (b[i])
16             for (j=0;j<(1<<n);j++)
17                 if (b[j])
18                     if ((i&j)==0 && (i&(j<<1))==0 && ((i<<1)&j)==0)
19                         a[i][j]=true;
20 }
21 int main(){
22     freopen ("king.in","r",stdin);freopen ("king.out","w",stdout);
23     LL i,j,k,x;
24     scanf("%lld%lld",&n,&m);
25     pre();
26     for (i=0;i<(1<<n);i++) if (b[i]) f[1][num[i]][i]=1;
27     for (i=1;i<n;i++)
28         for (j=0;j<(1<<n);j++) if (b[j])
29             for (k=0;k<(1<<n);k++) if (b[k] && a[j][k])
30                 for (x=num[j];x+num[k]<=m;x++)
31                     f[i+1][num[k]+x][k]+=f[i][x][j];
32     for (i=0;i<(1<<n);i++) ans+=f[n][m][i];
33     printf("%lld",ans);
34     return 0;
35 }
原文地址:https://www.cnblogs.com/keximeiruguo/p/7785914.html