ZJOI2017练习D3T2 road(斯坦纳树,状压DP)

Posted myx12345

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJOI2017练习D3T2 road(斯坦纳树,状压DP)相关的知识,希望对你有一定的参考价值。

题意:

对于边带权的无向图 G = (V, E),请选择一些边,

使得1<=i<=d,i号节点和 n ? i + 1 号节点可以通过选中的边连通,

最小化选中的所有边的权值和。

d<=4 n<=10000 m<=10000 w[i]<=1000

思路:

求一个最小生成树(或森林),使得若干组点对各自联通
由于d很小(<=4),考虑采用状压DP的做法。
令1,2,..d和n,n-1...n-d+1为2d个特殊点
先考虑生成树的情况:设F[i][j](i=1,2...n j为一个2d位的2进制)表示以第i个点为根,当前生成树包含特殊点的情况为j的最小代价
一共有两种转移方法:
① F[i][j]+F[i][k]-->F[i][j|k]
② F[i][j]+edg[i][k]-->F[k][j]
初始条件(d=3为例)F[1][000001]=F[2][000010]=F[3][000100]=F[n-2][001000]=F[n-1][010000]=F[n][100000]=0,其余F=inf
从小到大枚举j(0...1<<(2*d)-1)
对每个j,再枚举i和(j的一个子集k),F[i][j]=min{F[i][k]+F[i][j-k]}
对第二种转移按照多源最短路的方式跑spfa
得到F后再考虑怎么求生成森林答案
令G[i]表示当前点对联通状态为i时的最小代价(如i=011时表示第一个点对(1,n)不连通,第二和三个点对(2,n-1),(3,n-2)连通)
则G[i]=min{G[j]+G[i-j],F[k][p]}(j是i的子集,k=1,2,....n,p表示i代表的点对的所有点的状压形式,如i=001,代表(3,n-2),此时p=001100)}
最后答案就是G[(1<<d)-1]

时间复杂度:求F O(3^(2*d)*n /*第一步*/ + 2^(2*d)*spfa(n,m) /*第二步*/ ),求G复杂度远低于F,可忽略
空间复杂度:F数组O(n*2^(2*d)),G忽略

  1 const oo=1000000000;
  2 var head,vet,next,len:array[1..110000]of longint;
  3     dp:array[1..11000,0..1000]of longint;
  4     g:array[0..20000]of longint;
  5     q:array[0..20000]of longint;
  6     inq:array[1..20000]of boolean;
  7     n,m,sta,i,j,tot,d,x,y,z,s,v,sum:longint;
  8 
  9 function min(x,y:longint):longint;
 10 begin
 11  if x<y then exit(x);
 12  exit(y);
 13 end;
 14 
 15 procedure add(a,b,c:longint);
 16 begin
 17  inc(tot);
 18  next[tot]:=head[a];
 19  vet[tot]:=b;
 20  len[tot]:=c;
 21  head[a]:=tot;
 22 end;
 23 
 24 procedure spfa(sta:longint);
 25 var i,t,w,u,e,v:longint;
 26 begin
 27  t:=0; w:=0;
 28  for i:=1 to n do
 29  begin
 30   inc(w); q[w]:=i; inq[i]:=true;
 31  end;
 32  while t<w do
 33  begin
 34   inc(t); u:=q[t mod 20000]; inq[u]:=false;
 35   e:=head[u];
 36   while e<>0 do
 37   begin
 38    v:=vet[e];
 39    if dp[u,sta]+len[e]<dp[v,sta] then
 40    begin
 41     dp[v,sta]:=dp[u,sta]+len[e];
 42     if not inq[v] then
 43     begin
 44      inc(w); q[w mod 20000]:=v; inq[v]:=true;
 45     end;
 46    end;
 47    e:=next[e];
 48   end;
 49  end;
 50 end;
 51 
 52 begin
 53  assign(input,road.in); reset(input);
 54  assign(output,road.out); rewrite(output);
 55  readln(n,m,d);
 56  for i:=1 to m do
 57  begin
 58   readln(x,y,z);
 59   add(x,y,z);
 60   add(y,x,z);
 61  end;
 62  sum:=1<<(d<<1);
 63  for i:=1 to sum-1 do
 64   for j:=1 to n do dp[j,i]:=oo;
 65  for i:=1 to d do
 66  begin
 67   dp[i,1<<(i-1)]:=0;
 68   dp[n-i+1,1<<(i+d-1)]:=0;
 69  end;
 70 
 71  for sta:=1 to sum-1 do
 72  begin
 73   for i:=1 to n do
 74   begin
 75    v:=sta-1;
 76    while v>0 do
 77    begin
 78     dp[i,sta]:=min(dp[i,sta],dp[i,v]+dp[i,sta xor v]);
 79     v:=sta and (v-1);
 80    end;
 81   end;
 82   spfa(sta);
 83  end;
 84  sum:=1<<d;
 85  for sta:=1 to sum-1 do
 86  begin
 87   g[sta]:=oo;
 88   for i:=1 to n do g[sta]:=min(g[sta],dp[i,sta or (sta<<d)]);
 89  end;
 90  for sta:=1 to sum-1 do
 91  begin
 92   v:=sta-1;
 93   while v>0 do
 94   begin
 95    g[sta]:=min(g[sta],g[v]+g[sta xor v]);
 96    v:=sta and (v-1);
 97   end;
 98  end;
 99  if g[sum-1]<oo then writeln(g[sum-1])
100   else writeln(-1);
101 
102 
103  close(input);
104  close(output);
105 end.

 

以上是关于ZJOI2017练习D3T2 road(斯坦纳树,状压DP)的主要内容,如果未能解决你的问题,请参考以下文章

ZJOI2017线段树

[BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

ZJOI 2017 树状数组(线段树套线段树)

ZJOI2017练习D8T1 mushroom(点分治)

BZOJ4785[Zjoi2017]树状数组 树套树(二维线段树)

bzoj4785[Zjoi2017]树状数组 线段树套线段树