题目链接

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

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

什么是斯坦纳树呢?

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

可以发现,如果点集大小为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. java使用validator进行校验

    不管是html页面表单提交的对象数据还是和第三方公司进行接口对接,都需要对接收到的数据进行校验(非空.长度.格式等等).如果使用if一个个进行校验(字段非常多),这是让人崩溃的过程.幸好jdk或hib ...

  2. Notepad++ 用法技巧

    1 搜索技巧 [搜索中文]用正则表达式搜索:[一-龥] 2 用于SWIG语法的模板配置 notepad++是Windows平台上非常优秀的文本编辑器,速度快,功能强,还能自定义语言模板呢.很好用! 这 ...

  3. 腾讯云远程连接Kafka

    腾讯云服务器上部署Kafka,使用server.properties中公网IP配置: 启动时候报错: ERROR [KafkaServer id=0] Fatal error during Kafka ...

  4. opendir 、readdir 小结

    转载于:http://blog.csdn.net/lin_fs/article/details/7335573 1. opendir() 头文件 #include<sys/types.h> ...

  5. [转帖]PKI系统深入介绍

    PKI系统深入介绍 https://blog.csdn.net/liuhuiyi/article/details/7776825 2012年07月23日 20:17:01 liuhuiyi 阅读数 4 ...

  6. Idea 控制台Tomcat乱码设置

    找到tomcat安装目录,进入conf目录,找到logging.properties文件 把默认的 java.util.logging.ConsoleHandler.encoding = UTF-8 ...

  7. 【LOJ】#3095. 「SNOI2019」字符串

    LOJ#3095. 「SNOI2019」字符串 如果两个串\(i,j\)比较\(i < j\),如果离\(a_{i}\)最近的不同的数是\(a_{k}\),如果\(j < k\)那么\(i ...

  8. JSP与Servlet之间的交互,传值

    一.Servlet 首先要明白一点,servlet需要容器的支持才能够运行,如Tomcat.jetty 达到servlet的请求,需要ServletRequest对象和ServletResponse对 ...

  9. Linux系列(1):入门之基本命令详解

    Linux常用命令 声明: 作者使用的Linux是CentOS7版本. 本节主要讲解内容: 1.ls.date.bc.cal等指令的详细用法 2.介绍常用快捷键 3.了解磁盘分区以及挂载等概念 在Li ...

  10. tp5定时任务

    第一步: a.App/模块/ 下创建command文件夹 b.我这边是创建在crontab模块里面,在command文件夹下创建一个Task.php文件(具体名字自己根据需求定) c.复制下面的代码到 ...