[BZOJ1087][SCOI2005]互不侵犯King解题报告|状压DP
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
好像若干月前非常Naive地去写过DFS...
然后其实作为状压DP是一道非常好的题啦><
感觉直接无脑搞时间是下不来的 做了好几道预处理
使得最后DP的过程中没有任何一条转移是无用的
1 program bzoj1087; 2 var i,x,n,k,j,p,q,t1,t2:longint; 3 ans:int64; 4 a:array[-1..512]of longint; 5 b:array[-1..9,-1..100]of longint; 6 c:array[-1..512,-1..512]of longint; 7 f:array[0..1,-1..512,-1..512]of int64; 8 9 function check(x:longint):boolean; 10 var las:longint; 11 begin 12 las:=0; 13 while x<>0 do 14 begin 15 if (x and 1=1)and(las=1) then exit(false); 16 las:=x and 1; 17 x:=x >> 1; 18 end; 19 exit(true); 20 end; 21 22 function count(x:longint):longint; 23 var tem:longint; 24 begin 25 tem:=0; 26 while x<>0 do 27 begin 28 inc(tem,x and 1); 29 x:=x >> 1; 30 end; 31 exit(tem); 32 end; 33 34 function ok(x,y:longint):boolean; 35 var i:longint; 36 tmp:array[0..1,-1..10]of longint; 37 begin 38 for i:=8 downto 0 do tmp[0,i]:=x >> i and 1; 39 for i:=8 downto 0 do tmp[1,i]:=y >> i and 1; 40 for i:=0 to 8 do if (tmp[0,i]+tmp[1,i]=2)or(tmp[0,i]+tmp[1,i-1]=2)or(tmp[0,i]+tmp[1,i+1]=2) then exit(false); 41 exit(true); 42 end; 43 44 begin 45 fillchar(b,sizeof(b),0); 46 fillchar(a,sizeof(a),0); 47 fillchar(c,sizeof(c),0); 48 readln(n,k); 49 for i:=0 to 1 << n-1 do if check(i) then 50 begin 51 x:=count(i); 52 inc(b[x,0]);b[x,b[x,0]]:=i; 53 inc(a[0]);a[a[0]]:=i; 54 end; 55 for i:=1 to a[0] do 56 for j:=1 to a[0] do if ok(a[i],a[j]) then begin inc(c[a[i],0]);c[a[i],c[a[i],0]]:=a[j];end; 57 fillchar(f,sizeof(f),0); 58 for i:=0 to k do 59 for j:=1 to b[i,0] do f[1,i,b[i,j]]:=1; 60 for i:=2 to n do 61 begin 62 f[0]:=f[1]; 63 fillchar(f[1],sizeof(f[1]),0); 64 for j:=0 to k do 65 for p:=0 to (n+1) >> 1 do if p<=j then 66 begin 67 q:=j-p; 68 for t1:=1 to b[p,0] do 69 for t2:=1 to c[b[p,t1],0] do inc(f[1,j,b[p,t1]],f[0,q,c[b[p,t1],t2]]); 70 end; 71 end; 72 ans:=0; 73 for i:=1 to a[0] do inc(ans,f[1,k,a[i]]); 74 writeln(ans); 75 end.