您的位置:首页 > 其它

[BZOJ1087][SCOI2005]互不侵犯King解题报告|状压DP

2015-05-05 19:10 423 查看

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



  好像若干月前非常Naive地去写过DFS...

  然后其实作为状压DP是一道非常好的题啦><

  感觉直接无脑搞时间是下不来的 做了好几道预处理

  使得最后DP的过程中没有任何一条转移是无用的

  

program bzoj1087;
var i,x,n,k,j,p,q,t1,t2:longint;
ans:int64;
a:array[-1..512]of longint;
b:array[-1..9,-1..100]of longint;
c:array[-1..512,-1..512]of longint;
f:array[0..1,-1..512,-1..512]of int64;

function check(x:longint):boolean;
var las:longint;
begin
las:=0;
while x<>0 do
begin
if (x and 1=1)and(las=1) then exit(false);
las:=x and 1;
x:=x >> 1;
end;
exit(true);
end;

function count(x:longint):longint;
var tem:longint;
begin
tem:=0;
while x<>0 do
begin
inc(tem,x and 1);
x:=x >> 1;
end;
exit(tem);
end;

function ok(x,y:longint):boolean;
var i:longint;
tmp:array[0..1,-1..10]of longint;
begin
for i:=8 downto 0 do tmp[0,i]:=x >> i and 1;
for i:=8 downto 0 do tmp[1,i]:=y >> i and 1;
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);
exit(true);
end;

begin
fillchar(b,sizeof(b),0);
fillchar(a,sizeof(a),0);
fillchar(c,sizeof(c),0);
readln(n,k);
for i:=0 to 1 << n-1 do if check(i) then
begin
x:=count(i);
inc(b[x,0]);b[x,b[x,0]]:=i;
inc(a[0]);a[a[0]]:=i;
end;
for i:=1 to a[0] do
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;
fillchar(f,sizeof(f),0);
for i:=0 to k do
for j:=1 to b[i,0] do f[1,i,b[i,j]]:=1;
for i:=2 to n do
begin
f[0]:=f[1];
fillchar(f[1],sizeof(f[1]),0);
for j:=0 to k do
for p:=0 to (n+1) >> 1 do if p<=j then
begin
q:=j-p;
for t1:=1 to b[p,0] do
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]]);
end;
end;
ans:=0;
for i:=1 to a[0] do inc(ans,f[1,k,a[i]]);
writeln(ans);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: