bzoj1087: [SCOI2005]互不侵犯King (codevs2451) 状压dp
唔...今天学了状压就练练手...
这题的话,我感觉算是入门题了QAQ...
然而我还是想了好久...
大致自己推出了方程,但是一直挂,调了很久选择了题解 坚持不懈的努力的调代码。
然后发现题解的方程和我一毛一样呀QAQ
然后就又开始无限调调调QAQ最后发现自己统计答案没放循环里...气哇QAQ看都之后哇的一声哭出来。
好吧进入正题吧。
设 f[i,j,k] 表示 放到第 i 行,第 i 行状态为 j 且总共放了 k 个的方案数。
然后方程就是 f[i,j,k+num[j]]+=f[i-1,x,k]
就是枚举一个 x 表示 第 i-1 层的状态,然后判其是否合法。
刚开始的时候懒的预处理,后来发现预处理代码更短就改了QAQ是的我是懒兔纸。
所以我萌预处理一个 num[i] 表示 状态为 i 中的 1 个数有多少个,也就是放了多少个国王。
顺便对于 不合法的状态 i 的num[i]=-1
然后对于枚举的每一个 x 直接暴力判 j 和 x 这两个状态合起来后是否合法。
暴力判的原因是我懒得预处理QAQ
然后 就枚举 k 表示 前 i-1 行已经放了 k 个国王。
辣么k+num[j] 就是第 i 行放完后的个数。
显然 k 的范围是 num[x]<=k<=m-num[j]
然后就愉快的水过去了,虽然wa了一次,因为longlong。
总的来说今天的状态压缩学得还不错=v=
1 var 2 i,j,k,x:longint; 3 n,m:longint; 4 f:array[0..10,0..1200,0..105]of int64; 5 ans:int64; 6 num:array[0..1200]of longint; 7 function isnot(i,x:longint):boolean; 8 begin 9 exit((1 << (i-1))and x>0); 10 end; 11 function ok(x:longint):longint; 12 var i:longint; 13 num:longint; 14 begin 15 num:=0; 16 for i:=1 to n do 17 begin 18 if isnot(i,x) and((i>1)and isnot(i-1,x)) then exit(-1); 19 if isnot(i,x) then inc(num); 20 end; 21 exit(num); 22 end; 23 function check(x,y:longint):boolean; 24 var i:longint; 25 begin 26 for i:=1 to n do 27 begin 28 if isnot(i,x) then 29 if ((i>1)and(isnot(i-1,y)))or(isnot(i,y))or((i<n)and(isnot(i+1,y))) then exit(false); 30 end; 31 exit(true); 32 end; 33 begin 34 read(n,m); 35 f[0,0,0]:=1; 36 for j:=0 to (1 << n)-1 do 37 num[j]:=ok(j); 38 for i:=1 to n do 39 for j:=0 to (1 << n)-1 do 40 begin 41 if num[j]>=0 then 42 begin 43 for x:=0 to(1 << n)-1 do 44 if (num[x]>=0)and(check(j,x)) then 45 begin 46 for k:=num[x] to m do 47 if k+num[j]<=m then 48 inc(f[i,j,k+num[j]],f[i-1,x,k]); 49 end; 50 end; 51 if i=n then inc(ans,f[i,j,m]); 52 end; 53 writeln(ans); 54 end.