## 【BZOJ2595】游览计划（状压DP，斯坦纳树）

n,m,k<=10

dp[i,j,sta]表示以(i,j)为根，关键点联通情况为sta的最小花费

$dp[i,j,sta]=dp[i,j,x]+dp[i,j,sta xor x]-a[i,j]$ 即合并子集

$dp[i,j,sta]=dp[x,y,sta]+a[i,j]$  即合并道路

PS：其实暴力的想法：Sigma C(k,k-i)*2^i用二项式展开就是3^k啦（感谢邻桌数学国家队CWY同学）

  1 const oo=2000000000;
2       dx:array[1..4]of longint=(-1,1,0,0);
3       dy:array[1..4]of longint=(0,0,-1,1);
4 var dp:array[1..12,1..12,0..1100]of longint;
5     pre:array[1..12,1..12,0..1100,1..3]of longint;
6     flag,a,inq:array[1..12,1..12]of longint;
7     q:array[0..2000,1..3]of longint;
8     n,m,i,j,x,y,k,v,k1,t,w,sta,tmp,ux,uy:longint;
9
10 procedure dfs(i,j,sta:longint);
11 var x,y,z:longint;
12 begin
13  if sta=0 then exit;
14  flag[i,j]:=1;
15  x:=pre[i,j,sta,1]; y:=pre[i,j,sta,2]; z:=pre[i,j,sta,3];
16  dfs(x,y,z);
17  if (x=i)and(y=j) then dfs(x,y,sta xor z);
18 end;
19
20 procedure print(x,y:longint);
21 var i,j:longint;
22 begin
23  writeln(dp[x,y,(1<<k1)-1]);
24  fillchar(flag,sizeof(flag),0);
25  dfs(x,y,(1<<k1)-1);
26  for i:=1 to n do
27  begin
28   for j:=1 to m do
29    if a[i,j]>0 then
30    begin
31     if flag[i,j]=1 then write('o')
32      else write('_');
33    end
34     else write('x');
35   writeln;
36  end;
37 end;
38
39 begin
40  assign(input,'bzoj2595.in'); reset(input);
41  assign(output,'bzoj2595.out'); rewrite(output);
43  for i:=1 to n do
44   for j:=1 to m do read(a[i,j]);
45  fillchar(dp,sizeof(dp),\$7f);
46  for i:=1 to n do
47   for j:=1 to m do
48    if a[i,j]=0 then
49    begin
50     inc(k1); dp[i,j,1<<(k1-1)]:=0;
51    end;
52  for v:=1 to (1<<k1)-1 do
53  begin
54   fillchar(inq,sizeof(inq),0);
55   t:=0; w:=0;
56   for i:=1 to n do
57    for j:=1 to m do
58    begin
59     x:=v and (v-1);
60     while x>0 do
61     begin
62      tmp:=dp[i,j,x]+dp[i,j,v xor x]-a[i,j];
63      if tmp<dp[i,j,v] then
64      begin
65       dp[i,j,v]:=tmp;
66       pre[i,j,v,1]:=i; pre[i,j,v,2]:=j; pre[i,j,v,3]:=x;
67      end;
68      x:=v and (x-1);
69     end;
70     if dp[i,j,v]<oo then begin inc(w); q[w,1]:=i; q[w,2]:=j; inq[i,j]:=1; end;
71    end;
72    while t<w do
73    begin
74     inc(t); ux:=q[t mod 2000,1]; uy:=q[t mod 2000,2]; inq[ux,uy]:=0;
75     for k:=1 to 4 do
76     begin
77      x:=ux+dx[k]; y:=uy+dy[k];
78      if (x>0)and(x<=n)and(y>0)and(y<=m)and(dp[ux,uy,v]+a[x,y]<dp[x,y,v]) then
79      begin
80       dp[x,y,v]:=dp[ux,uy,v]+a[x,y];
81       pre[x,y,v,1]:=ux; pre[x,y,v,2]:=uy; pre[x,y,v,3]:=v;
82       if inq[x,y]=0 then
83       begin
84        inc(w); q[w mod 2000,1]:=x; q[w mod 2000,2]:=y; inq[x,y]:=1;
85       end;
86      end;
87     end;
88    end;
89  end;
90
91
92
93  for i:=1 to n do
94  begin
95   for j:=1 to m do
96    if a[i,j]=0 then begin print(i,j); break; end;
97   if a[i,j]=0 then break;
98  end;
99  close(input);
100  close(output);
101 end.

posted on 2016-12-22 20:31  myx12345  阅读(148)  评论(0编辑  收藏  举报