题目链接

题目大意:有一张无向图,每条边有一定的花费,给出一些点集,让你从中选出一些边,用最小的花费将每个点集内的点相互连通,可以使用点集之外的点(如果需要的话)。

算是斯坦纳树的入门题吧。

什么是斯坦纳树呢?

假定有这样的题目:给你一张无向图和一个点集,每条边有一定的花费,让你选出一些边使点集内的所有点连通,求最小花费。

可以发现,如果点集大小为2,那么就转化成了一个两点间最短路问题。

而如果点集大小为总点数,那么就转化成了一个最小生成树问题。

进一步可以推出,如果点集大小为3,那么答案就相当于选出一个点,使该点到点集内三点的距离之和最短。

那么如果点集大小为4,5,...,乃至更多,怎么办?

随着点集的增加,情况也会越来越复杂,好像一时难以找到突破点。

其实这类题有着通用的解法,也就是斯坦纳树的dp。

设$dp[S][i]$为构造出以i为根(选根只是为了方便转移,无实际意义,相当于无根树转有根树),连通的点集为S的树的最小化费,则初始状态为$dp[1<<i][i]=0$,且存在两类转移:

$dp[S][i]=\left\{\begin{matrix}\begin{aligned}&min\{dp[S'][i]+dp[S\oplus S'][i]\}\\&min\{dp[S][j]+d[j][i]\}\end{aligned}\end{matrix}\right.$

其中$S'$是$S$的子集,$d[j][i]$表示点j与点i直接相连的边的花费。

其中第一类转移是有序的,可以直接dp求解;而第二类是无序的,需要用SPFA求解(用Dijkstra理论上也可以,但通常SPFA更快)

这样的转移还存在一个问题,就是有些边可能会重复经过,但总会存在一个不会重复的最优解,所以可以忽略掉这个问题。

这是只有一个点集时的情况,如果有多个点集的话只需要再加一个转移就好了:

$mi[S]=min\{mi[S']+mi[S\oplus S']\}$

其中$mi[S]$表示将点集S连通的最小花费,初始值为$mi[S]=min\{dp[S][i]\}$,且$S$和$S\oplus S'$都要满足:对于任意一个点集中的点,要么不包含,要么全部包含。

复杂度$O(n(3^k+Am2^k))$,A为SPFA的常数,一般较小。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+,inf=0x3f3f3f3f;
int n,m,k,hd[N],ne,inq[N],dp[<<][N],mi[<<],SS[+],Y[N],X[N],ok[<<];
struct E {int v,c,nxt;} e[N*];
void addedge(int u,int v,int c) {e[ne]= {v,c,hd[u]},hd[u]=ne++;}
queue<int> q;
void upd(int u,int c,int S) {
if(dp[S][u]>c) {dp[S][u]=c; if(!inq[u])inq[u]=,q.push(u);}
}
void spfa(int S) {
while(q.size())q.pop();
memset(inq,,sizeof inq);
for(int i=; i<=n; ++i)if(dp[S][i]!=inf)q.push(i),inq[i]=;
while(q.size()) {
int u=q.front();
q.pop(),inq[u]=;
for(int i=hd[u]; ~i; i=e[i].nxt)upd(e[i].v,dp[S][u]+e[i].c,S);
}
}
int main() {
memset(hd,-,sizeof hd),ne=;
scanf("%d%d%d",&n,&m,&k);
while(m--) {
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c);
addedge(v,u,c);
}
for(int i=; i<k; ++i) {
int a,b;
scanf("%d%d",&a,&b);
Y[b]=i,X[i]=b;
SS[a]|=<<i;
}
for(int i=; i<=; ++i)if(SS[i])ok[SS[i]]=;
for(int i=; i<=n; ++i)spfa(i);
memset(dp,inf,sizeof dp);
for(int i=; i<k; ++i)dp[<<i][X[i]]=;
for(int S=; S<(<<k); ++S) {
for(int S2=(S-)&S; S2; S2=(S2-)&S)
for(int i=; i<=n; ++i)
dp[S][i]=min(dp[S][i],dp[S2][i]+dp[S^S2][i]);
spfa(S);
mi[S]=inf;
for(int i=; i<=n; ++i)mi[S]=min(mi[S],dp[S][i]);
}
for(int S=; S<(<<k); ++S)
for(int S2=(S-)&S; S2; S2=(S2-)&S)if(ok[S2]&&ok[S^S2])
mi[S]=min(mi[S],mi[S2]+mi[S^S2]),ok[S]=;
printf("%d\n",mi[(<<k)-]);
return ;
}

洛谷P3264 [JLOI2015]管道连接 (斯坦纳树)的更多相关文章

  1. BZOJ 4006 Luogu P3264 [JLOI2015]管道连接 (斯坦纳树、状压DP)

    题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4006 (luogu)https://www.luogu.org/probl ...

  2. 洛谷P3264 [JLOI2015]管道连接(斯坦纳树)

    传送门 感觉对斯坦纳树还是有很多疑惑啊…… 等到时候noip没有爆零的话再回来填坑好了 //minamoto #include<iostream> #include<cstdio&g ...

  3. BZOJ4006 JLOI2015 管道连接(斯坦纳树生成森林)

    4006: [JLOI2015]管道连接 Time Limit: 30 Sec Memory Limit: 128 MB Description 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的 ...

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

    Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1171  Solved: 639[Submit][Status][Discuss] Descripti ...

  5. 【bzoj4006】[JLOI2015]管道连接 斯坦纳树+状压dp

    题目描述 给出一张 $n$ 个点 $m$ 条边的无向图和 $p$ 个特殊点,每个特殊点有一个颜色.要求选出若干条边,使得颜色相同的特殊点在同一个连通块内.输出最小边权和. 输入 第一行包含三个整数 n ...

  6. 【BZOJ4774/4006】修路/[JLOI2015]管道连接 斯坦纳树

    [BZOJ4774]修路 Description 村子间的小路年久失修,为了保障村子之间的往来,法珞决定带领大家修路.对于边带权的无向图 G = (V, E),请选择一些边,使得1 <= i & ...

  7. bzoj 4006 [JLOI2015]管道连接——斯坦纳树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4006 除了模板,就是记录 ans[ s ] 表示 s 合法的最小代价.合法即保证 s 里同一 ...

  8. 洛谷 P7450 - [THUSCH2017] 巧克力(斯坦纳树+随机化)

    洛谷题面传送门 9.13 补之前 8.23 做的题,不愧是鸽子 tzc( 首先我们先来探讨一下如果 \(c_{i,j}\le k\) 怎么做,先考虑第一问.显然一个连通块符合条件当且仅当它能够包含所有 ...

  9. bzoj 4006 管道连接 —— 斯坦纳树+状压DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4006 用斯坦纳树求出所有关键点的各种连通情况的代价,把这个作为状压(压的是集合选择情况)的初 ...

随机推荐

  1. Android笔记01--手机振动

    一.android任务栈  不懂? 栈:先进后出 队列:先进先出 任务栈Task中:打开一个Activity叫进栈 关闭一个activit出栈 任务栈是用来维护Activity的.是用来维护用户的操作 ...

  2. 【NOIP2015普及组】 推销员(纪中数据-标准)

    题目 [题目描述] 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户.螺丝街一共有 N 家住户,第 i 家住户到入口的距离为 ...

  3. HTML 标签的 for 属性

    HTML 标签的 for 属性 for 属性规定 label 与哪个表单元素绑定. 隐式和显式的联系 label通常以下面两种方式中的一种来和表单控件相联系: 将表单控件作为标记标签的内容,这样的就是 ...

  4. PHP 协程:Go + Chan + Defer

    Swoole4为PHP语言提供了强大的CSP协程编程模式.底层提供了3个关键词,可以方便地实现各类功能. Swoole4提供的PHP协程语法借鉴自Golang,在此向GO开发组致敬 PHP+Swool ...

  5. GukiZ and Binary Operations CodeForces - 551D (组合计数)

    大意: 给定$n,k,l,m$, 求有多少个长度为$n$, 元素全部严格小于$2^l$, 且满足 的序列. 刚开始想着暴力枚举当前or和上一个数二进制中$1$的分布, 但这样状态数是$O(64^3)$ ...

  6. Scala学习三——数组相关操作

    一.若长度固定则使用Array,若长度可能有变化则使用ArrayBuffer 固定长度数组: 如val nums=new Array[Int](10) //10个整型数组,所有元素初始化为0; val ...

  7. vs 2013 设置website项目端口

    vs 2015/2013 设置website项目端口 在web项目创建之后,当我想重新debug时,出现the port xxx is in use 错误. 经过netstat分析,发现占用此项目端口 ...

  8. PMP - 控制图(质量控制工具)

    这里用一个具体例子来解释什么是控制图. 假设现在工厂需要生成直径为1000mm (允许偏差为振幅4个标准差,即:±4mm)的螺丝钉.我们要如何保证生成过程的质量呢? 这时候我们应该对生成出来的产品进行 ...

  9. 04 Go语言之包

    1.为什么有包这个概念? 1)开发中,往往要在不同的文件中调用其他文件的函数 2)Go代码最小粒度单位是”包” 3)go的每一个文件都属于一个包,通过package管理 4)go以包的形式管理文件和项 ...

  10. python版本

    一般在Linux下,默认会安装一个python2.*的版本,但是我们自己开发有时候需要python3.*的版本 1. 安装python3 .安装依赖包 )首先安装gcc编译器,gcc有些系统版本已经默 ...