互不侵犯(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.

 

你可能感兴趣的:(ZOJ)