【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.
时间: 2024-08-07 00:53:30

【ZJOI2017练习】D3T2 road(斯坦纳树,状压DP)的相关文章

BZOJ2595: [Wc2008]游览计划(斯坦纳树,状压DP)

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2030  Solved: 986[Submit][Status][Discuss] Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Outpu

BZOJ4006: [JLOI2015]管道连接(斯坦纳树,状压DP)

Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1171  Solved: 639[Submit][Status][Discuss] Description 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰. 该部门有 n 个情报站,用 1 到 n 的整数编号.给出 m 对情报站 ui;vi 和费用 wi,表示情 报站 ui 和 vi 之间可以花费 wi 单位资源建立通道. 如果一个情报站经过若干个建立好的通道可以到达另外一个情报

HDU 4085 Peach Blossom Spring 斯坦纳树 状态压缩DP+SPFA

状态压缩dp+spfa解斯坦纳树 枚举子树的形态 dp[i][j] = min(dp[i][j], dp[i][k]+dp[i][l]) 其中k和l是对j的一个划分 按照边进行松弛 dp[i][j] = min(dp[i][j], dp[i'][j]+w[i][j])其中i和i'之间有边相连 #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn

【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)

2595: [Wc2008]游览计划 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1572  Solved: 739 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Output 由 N

BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】

传送门 题意:略 论文 <SPFA算法的优化及应用> http://www.cnblogs.com/lazycal/p/bzoj-2595.html 本题的核心就是求斯坦纳树: Steiner Tree: Given an undirected graph with non-negative edge weights and a subset of vertices, usually referred to as terminals, the Steiner tree problem in g

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

【BZOJ2595】【Wc2008】游览计划、斯坦纳树

题解:斯坦纳树,实现神马的在代码里面有还看得过去的注释. 代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 15 #define inf 0x3f3f3f3f using namespace std; const int dx[]={0,0,1,-1}; const int dy[

【bzoj5180】[Baltic2016]Cities 斯坦纳树

题目描述 给定n个点,m条双向边的图.其中有k个点是重要的.每条边都有一定的长度. 现在要你选定一些边来构成一个图,要使得k个重要的点相互连通,求边的长度和的最小值. 输入 共m+2行 第1行:n,k,m,n个点,k个重要的点,m条边: 第2行共K个点 第3至第m+2行,每行包括3个数字,a,b,c,表示有一条从a到b长度为c的双向路径 k<=5 n<=10^5 1<=m<=2*(10^5) 输出 共1行,即最小长度和 样例输入 4 3 61 3 41 2 41 3 91 4 62

FJoi2017 1月20日模拟赛 直线斯坦纳树(暴力+最小生成树+骗分+人工构造+随机乱搞)

[题目描述] 给定二维平面上n个整点,求该图的一个直线斯坦纳树,使得树的边长度总和尽量小. 直线斯坦纳树:使所有给定的点连通的树,所有边必须平行于坐标轴,允许在给定点外增加额外的中间节点. 如下图所示为两种直线斯坦纳树的生成方案,蓝色点为给定的点,红色点为中间节点. [输入格式] 第一行一个整数n,表示点数. 以下n行,每行两个整数表示点的x,y坐标. [输出格式] 第一行一个整数m,表示中间节点的个数. 必须满足m <= 10 * n 以下m行,每行2个整数表示中间节点的坐标. 以下n+m-1