前言:
 
 
如果还不知道斯坦纳树的童鞋可以看这两篇博客:
我的:https://blog.csdn.net/jerry_wang119/article/details/80001711
我一开始学习的:https://blog.csdn.net/wu_tongtong/article/details/78992913
这道题,在我学习斯坦纳树之前就翻到了,是在洛谷上搜状压的时候看到的。那个时候还不知道斯坦纳树是个什么玩意,不过马上进行了学习。
然而学习了之后也没有什么卵用,发现并不只是斯坦纳树这么简单呐!
 
 
题解:
 
 
由于存在相同频率之间的连通,所以和一般的斯坦纳树是不同的(发现斯坦纳树所指定的结点频率是相同的),需要二次DP。
 
首先跑一遍斯坦纳树的板子,这就求出了 以某一个结点为树根并加入一些边使某几个点连通的最小值,那么我们可以用这个去更新另一个 DP 数组:Ans(S)。

方程:Ans(S)= minx(Ans(S),dp(i,S));

定义 DP 数组 Ans (S),表示使状态 S 中所有点连通的最小费用,注意,这个 DP 的过程是有条件的:
 
首先枚举 S 集合(指定点集合),这个将这个状态 S 进行更新的条件是 S 必须:对于一个频率,要么包含该频率中的所有指定点,要么不包含于这个频率的任意结点!
 
接着枚举 S 的子集,这个子集 S1 也是要有条件的,也是 必须:对于一个频率,要么包含该频率中的所有指定点,要么不包含于这个频率的任意结点!
 
得到DP方程:Ans(S) = min(Ans(S),Ans(S1)+Ans(S^S1));
 
这样最后的答案就是 Ans(1<<(p)-1);
 
为什么要这样做呢?这样做不是和斯坦纳树中的 dp(i,S)数组重复了吗?
 
然而却有很大的区别,这样的 Ans(S)是使得 S 中相同的频率连通,而不是 S 中的所有点都连通!因为用于更新 S 的子集也满足这个条件,而 子集 和 子集对于 S 的补集没有联系,换句话说,两个子集内结点的连通互补干涉。
 

而加上频率的限制:

可以看出我们完全不用连边 2-5,因为这条边不改变相同频率的连通性!

所以带条件 Ans(S)经过DP更新后一定是最优解,并且保证没有额外边。

代码:

#include <bits/stdc++.h>

std :: queue < int >  q ;

const  int  N =  +  ;

struct  node {
int id , clr ;
}
dot [ ] ; int head [ N << ] , nxt [ N << ] , dis [ N << ] , to [ N << ] , cn ;
int dp [ N ] [ << ] , ans [ << ] , cnt [ ] , sum [ ] , n , m , p , S , x , y , w , inf ;
bool vis [ N ] , ck [ << ] ; int minx ( int a , int b ) {
return a > b ? b : a ;
} void create ( int u , int v , int d ) {
cn ++ ;
to [ cn ] = v ;
dis [ cn ] = d ;
nxt [ cn ] = head [ u ] ;
head [ u ] = cn ;
} void spfa ( int S ) {
for ( int i = ; i <= n ; i ++ )
if ( dp [ i ] [ S ] < inf )
vis [ i ] = true , q . push ( i ) ;
while ( ! q . empty ( ) ) {
int v , tmp = q . front ( ) ;
q . pop ( ) ; vis [ tmp ] = false ;
for ( int i = head [ tmp ] ; i ; i = nxt [ i ] ) {
v = to [ i ] ;
if ( dp [ v ] [ S ] > dp [ tmp ] [ S ] + dis [ i ] ) {
dp [ v ] [ S ] = dp [ tmp ] [ S ] + dis [ i ] ;
if ( ! vis [ v ] ) {
vis [ v ] = true ;
q . push ( v ) ;
}
}
}
}
} bool check ( int S ) {
memset ( cnt , , sizeof ( cnt ) ) ;
for ( int i = ; i <= p ; i ++ )
if ( S & ( << ( i - ) ) )
cnt [ dot [ i ] . clr ] ++ ;
for ( int i = ; i <= ; i ++ )
if ( cnt [ i ] && cnt [ i ] != sum [ i ] )
return ;
return ;
} int main ( ) { scanf ( "%d%d%d" , & n , & m , & p ) ;
memset ( dp , / , sizeof ( dp ) ) ;
inf = dp [ ] [ ] ;
S = ( << p ) - ;
for ( int i = ; i <= m ; i ++ ) {
scanf ( "%d%d%d" , & x , & y , & w ) ;
create ( x , y , w ) ;
create ( y , x , w ) ;
}
for ( int i = ; i <= p ; i ++ ) {
scanf ( "%d%d" , & dot [ i ] . clr , & dot [ i ] . id ) ;
sum [ dot [ i ] . clr ] ++ ;
}
for ( int i = ; i <= p ; i ++ )
dp [ dot [ i ] . id ] [ << ( i - ) ] = ;
for ( int s = ; s <= S ; s ++ ) {
for ( int i = ; i <= n ; i ++ )
for ( int s1 = s ; s1 ; s1 = ( s1 - ) & s )
dp [ i ] [ s ] = minx ( dp [ i ] [ s ] , dp [ i ] [ s1 ] + dp [ i ] [ s ^ s1 ] ) ;
spfa ( s ) ;
}
memset ( ans , / , sizeof ( ans ) ) ;
for ( int s = ; s <= S ; s ++ )
for ( int i = ; i <= n ; i ++ )
ans [ s ] = minx ( ans [ s ] , dp [ i ] [ s ] ) ;
for ( int s1 = ; s1 <= S ; s1 ++ )
if ( check ( s1 ) )
ck [ s1 ] = true ;
for ( int s = ; s <= S ; s ++ )
if ( ck [ s ] )
for ( int s1 = s ; s1 ; s1 = ( s1 - ) & s )
if ( ck [ s1 ] )
ans [ s ] = minx ( ans [ s ] , ans [ s1 ] + ans [ s ^ s1 ] ) ;
printf ( "%d" , ans [ S ] ) ;
return ;
}

Ans for this

要开O2,因为STL队列很慢。

【洛谷】 3264 [JLOI2015] 管道连接的更多相关文章

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

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

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

    题目链接 题目大意:有一张无向图,每条边有一定的花费,给出一些点集,让你从中选出一些边,用最小的花费将每个点集内的点相互连通,可以使用点集之外的点(如果需要的话). 算是斯坦纳树的入门题吧. 什么是斯 ...

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

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

  4. BZOJ_4006_[JLOI2015]管道连接_斯坦纳树

    BZOJ_4006_[JLOI2015]管道连接_斯坦纳树 题意: 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰. 该部门有 n 个情报站,用 1 到 n 的整数编号.给出 m ...

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

    4006: [JLOI2015]管道连接 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1020  Solved: 552[Submit][Statu ...

  6. [bzoj4006][JLOI2015]管道连接_斯坦纳树_状压dp

    管道连接 bzoj-4006 JLOI-2015 题目大意:给定一张$n$个节点$m$条边的带边权无向图.并且给定$p$个重要节点,每个重要节点都有一个颜色.求一个边权和最小的边集使得颜色相同的重要节 ...

  7. 洛谷 P3263 [JLOI2015]有意义的字符串

    洛谷 首先,看到\((\frac{(b+\sqrt{d})}{2})^n\),很快能够想到一元二次方程的解\(\frac{-b\pm\sqrt{\Delta}}{2a}\). 所以可以推出,\(\fr ...

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

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

  9. luogu P3264 [JLOI2015]管道连接

    LINK:管道连接 一张无向图 有P个关键点 其中有K个集合 各个集合要在图中形成联通块 边有边权 求最小代价. 其实还是生成树问题 某个点要和某个点要在生成树中 类似这个意思. 可以发现 是斯坦纳树 ...

随机推荐

  1. JQuery学习---JQuery深入学习

    属性操作 $("p").text()    $("p").html()   $(":checkbox").val() $(".te ...

  2. Windows as a Service(1)—— Windows 10服务分支

    前言 作为公司的IT管理员,管理全公司Windows 10操作系统的更新一直是工作中的头疼之处.微软提供了很多方法来帮助我们管理公司的Windows 10更新,比如Windows Server Upd ...

  3. setfacl 命令的常用用法

    setfacl命令----可以用来细分linux下的文件权限. chmod命令----可以把文件权限分为u,g,o三个组,而setfacl可以对每一个文件或目录设置更精确的文件权限. 换句话说,set ...

  4. Kinaba 简单画图

    此片文章简单介绍如何在kinaba 上画图. 如果你,还没有搭建ELK 请参考:ELK日志分析平台搭建全过程 本文参考:http://www.cnblogs.com/hanyifeng/p/58607 ...

  5. 重装win7系统的过程

    U盘重装系统准备工作: 1.下载一个制作U盘系统的软件,随便哪个都行,把U盘变成系统盘 2.下载镜像,将镜像copy到系统盘内即可(无需解压) 3.进入BIOS系统,将boot进行设置,将U盘设置为第 ...

  6. Apache Jemeter 开发插件

    为什么选择使用JMeter 当被问到这个问题的时候,也许你会在脑海里产生很多的理由,比如: Apache基金会下的开源项目,没有版权问题: 为数不多的还在持续更新的开源性能自动化测试工具: 支持协议丰 ...

  7. Linux和Unix的区别

    Linux      Unix 免费        收费 开源        不开源 硬件无要求   有要求 IBM Sun Hp 主流的Linux的发型版本: RedHat Fedora  Mand ...

  8. Python读取Json字典写入Excel表格的方法

    需求: 因需要将一json文件中大量的信息填入一固定格式的Excel表格,单纯的复制粘贴肯定也能完成,但是想偷懒一下,于是借助Python解决问题. 环境: Windows7 +Python2.7 + ...

  9. unbuntu 14安装 golang

    golang目前有两种编译,一种是golang官方提供的,另外一个是gnu提供的gccgo.这里安装的是Golang,从仓库安装(apt-get)        sudo apt-get instal ...

  10. 【[JSOI2007]建筑抢修】

    各种瞎写 之后也不知道为什么就过了 刚看到这道题感觉确实是不会的,因为我贪心太差了\(QAQ\) 之后就随便\(yy\)呗 发现首先我们得排一下序,以\(t2\)也就是建筑的损坏时间为第一关键字从小到 ...