【ZJOI2017 Round1练习&BZOJ4774】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.