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