互不侵犯(BZOJ1087) 题解

【题目描述】

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

【样例输入】

    3 2

【样例输出】

    16

【解题思路】

    本题为SCOI2005的题,正解应该是状态压缩动态规划,把所有方案变为二进制存储,1为该位置摆放了国王,0为没有,因为一行最多九个格子,也就是说最多为511,空间上完全可以接受。然后我们可以先预处理一下所有可行的国王摆放的位置,以减少动规的次数,设f[i,j,k]为现在是第i行,用第j种方案,一共摆放了k个国王的总方案数,那么我们动规的条件就是f[i,j,k]=∑f[i-1,s,t]{s为与j不冲突的方案,t<=k}

    于是对于每个可行方案,我们需要记录一些东西:这个可行方案摆了多少国王,这个可行方案的攻击范围。那么满足条件的s即为s and j=0。

【代码实现】

 1 type rec=record
 2      j,l,p:longint;
 3 end;
 4 var f:array[1..9,0..512,0..80] of int64;
 5     n,m,i,j,w,k,q,total,l:longint;
 6     ans:int64;
 7     fl:boolean;
 8     fa:array[1..500] of rec;
 9 procedure dfs(w,dep,t:longint);
10 var i:longint;
11     s:string;
12     ch:string;
13 begin
14  if dep>n then
15   begin
16    inc(total);
17    fa[total].j:=t;
18    i:=t;
19    s:='';
20    while i<>0 do
21     begin
22      if i and 1=1 then
23       inc(fa[total].l);
24      str(i and 1,ch);
25      s:=ch+s;
26      i:=i shr 1;
27     end;
28    while length(s)<n do
29     s:='0'+s;
30    for i:=n downto 1 do
31     if i=1 then
32      begin
33       if (s[i]='1')or(s[i+1]='1') then
34        fa[total].p:=fa[total].p+(1 shl (n-i));
35      end
36     else
37      if i=n then
38       begin
39        if (s[i]='1')or(s[i-1]='1') then
40         fa[total].p:=fa[total].p+1;
41       end
42      else
43       if (s[i]='1')or(s[i-1]='1')or(s[i+1]='1') then
44        fa[total].p:=fa[total].p+(1 shl (n-i));
45    exit;
46   end;
47  if w=1 then
48   dfs(0,dep+1,t)
49  else
50   for i:=0 to 1 do
51    begin
52     t:=t+i shl (dep-1);
53     dfs(i,dep+1,t);
54    end;
55 end;
56 begin
57  readln(n,m);
58  if m>sqr((n+1)shr 1) then
59   begin
60    writeln(0);
61    halt;
62   end;
63  dfs(0,1,0);
64  for i:=1 to total do
65   f[1,fa[i].j,fa[i].l]:=1;
66  for i:=2 to n do
67   for j:=1 to total do
68    for l:=0 to ((n+1)shr 1)*(i-1) do
69     if f[i-1,fa[j].j,l]=0 then
70      continue
71     else
72      for k:=1 to total do
73       if fa[j].p and fa[k].j=0 then
74        inc(f[i,fa[k].j,l+fa[k].l],f[i-1,fa[j].j,l]);
75  for i:=1 to total do
76   ans:=ans+f[n,fa[i].j,m];
77  writeln(ans);
78 end.

 

你可能感兴趣的:(互不侵犯(BZOJ1087) 题解)