SSL 1383 车Ⅱ 状压dp

来源:互联网 发布:淘宝主图1920显示不全 编辑:程序博客网 时间:2024/05/20 00:11

有一个n*m的棋盘(n、m≤80,n*m≤80)要在棋盘上放k(k≤20)个棋子,使得任意两个棋子不相邻。求合法的方案总数。

我们用数组s保存一行中所有的num个放置方案,则s数组可以在预处理过程中用DFS求出,同时用ci保存第i个状态中1的个数以避免重复计算。开始设计状态。本题状态的维数需要增加,原因在于并不是每一行只放一个棋子,也不是每一行都要求有棋子,原先的表示方法已经无法完整表达一个状态。我们用fi,j,k表示第i行的状态为sj且前i行总共放置k个棋子(下面用pn代替原题中的k)的方案数。沿用枚举当前行方案的做法,只要当前行的放置方案和上一行的不冲突。微观地讲,就是要两行的状态s1和s2中没有同为1的位即可,亦即s1&s2=0。然而,虽然我们枚举了第i行的放置方案,但却不知道其上一行(第i-1行)的方案。为了解决这个问题,我们不得不连第i-1行的状态一起枚举
代码:

<pre name="code" class="plain">var  d:array[1..10] of longint;  a,b:array[1..100] of longint;  f:array[0..80,0..1000,0..10] of longint;  ans,n,m,p,i,j,k,l,a1:longint;procedure dfs(x:longint);var  i:longint;begin  if x>m then  begin    inc(a1);    for i:=1 to m do    begin      a[a1]:=a[a1]+(1 shl (i-1))*d[i];      inc(b[a1],d[i]);    end;    exit;  end;  dfs(x+1);  d[x]:=1;  dfs(x+2);  d[x]:=0;end;begin  readln(n,m,p);  if n<m then  begin    n:=n xor m; m:=n xor m; n:=n xor m;  end;  dfs(1);  f[0,0,0]:=1;  for i:=1 to n do    for j:=0 to p do      for k:=1 to a1 do        if j>=b[k] then          for l:=1 to a1 do            if a[k] and a[l]=0 then              f[i,a[k],j]:=f[i,a[k],j]+f[i-1,a[l],j-b[k]];  for i:=1 to a1 do    ans:=ans+f[n,a[i],p];  writeln(ans);end.


0 0
原创粉丝点击