前言:
 
 
如果还不知道斯坦纳树的童鞋可以看这两篇博客:

我的: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 = 2000 + 5 ;struct  node {int  id , clr ;
}
dot [ 20 ] ;int  head [ N << 3 ] , nxt [ N << 3 ] , dis [ N << 3 ] , to [ N << 3 ] , cn ;
int  dp [ N ] [ 1 << 11 ] , ans [ 1 << 11 ] , cnt [ 30 ] , sum [ 30 ] , n , m , p , S , x , y , w , inf ;
bool  vis [ N ] , ck [ 1 << 11 ] ;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 = 1 ; 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 , 0 , sizeof ( cnt ) ) ;for ( int  i = 1 ; i <= p ; i ++ )if ( S & ( 1 << ( i - 1 ) ) )cnt [ dot [ i ] . clr ] ++ ;for ( int  i = 1 ; i <= 10 ; i ++ )if ( cnt [ i ]  &&  cnt [ i ]  !=  sum [ i ] )return  0 ;return  1 ;
}int  main ( ) {scanf ( "%d%d%d" , & n , & m , & p ) ;memset ( dp , 127 / 3 , sizeof ( dp ) ) ;inf = dp [ 0 ] [ 0 ] ;S = ( 1 << p ) - 1 ;for ( int  i = 1 ; i <= m ; i ++ ) {scanf ( "%d%d%d" , & x , & y , & w ) ;create ( x , y , w ) ;create ( y , x , w ) ;}for ( int  i = 1 ; i <= p ; i ++ ) {scanf ( "%d%d" , & dot [ i ] . clr , & dot [ i ] . id ) ;sum [ dot [ i ] . clr ] ++ ;}for ( int  i = 1 ; i <= p ; i ++ )dp [ dot [ i ] . id ] [ 1 << ( i - 1 ) ] = 0 ; for ( int  s = 0 ; s <= S ; s ++ ) {for ( int  i = 1 ; i <= n ; i ++ )for ( int  s1 = s ; s1 ; s1 = ( s1 - 1 ) & s )dp [ i ] [ s ] = minx ( dp [ i ] [ s ] , dp [ i ] [ s1 ] + dp [ i ] [ s ^ s1 ] ) ;spfa ( s ) ;}memset ( ans , 127 / 3 , sizeof ( ans ) ) ;for ( int  s = 0 ; s <= S ; s ++ )for ( int  i = 1 ; i <= n ; i ++ )ans [ s ] = minx ( ans [ s ] , dp [ i ] [ s ] ) ;for ( int  s1 = 0 ; s1 <= S ; s1 ++ )if ( check ( s1 ) )ck [ s1 ] = true ;for ( int  s = 0 ; s <= S ; s ++ )if ( ck [ s ] ) for ( int  s1 = s ; s1 ; s1 = ( s1 - 1 ) & s )if ( ck [ s1 ] )ans [ s ] = minx ( ans [ s ] , ans [ s1 ] + ans [ s ^ s1 ] ) ;printf ( "%d" , ans [ S ] ) ;return  0 ;
}

Ans for this

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

转载于:https://www.cnblogs.com/horsepower2001/p/9153410.html

【洛谷】 3264 [JLOI2015] 管道连接相关推荐

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

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

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

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

  3. 洛谷 - P1758 [NOI2009]管道取珠(计数dp)

    题目链接:点击查看 题目大意:给出两个长度分别为 n 和 m 的管道,每个管道中都只有两种颜色的珠子,现在可以按照规则组成序列,共可以组成 C( n+m , n ) 个序列,假设共组成了 K 种不同的 ...

  4. [JLOI2015]管道连接(斯坦纳树)

    [Luogu3264] 原题解 多个频道,每个频道的关键点要求相互联通 详见代码,非常巧妙 #include<cstdio> #include<iostream> #inclu ...

  5. 洛谷P1758 [NOI2009]管道取珠(dp 贡献转化)

    题目 bzoj1566 两个管道的小球序列, 分别用长为n(n<=500)和长为m(m<=500)的仅由A和B构成的字符串表示 两个管道归并的时候,每次可以从上管道取一个球,也可以从下管道 ...

  6. bzoj4006: [JLOI2015]管道连接

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4006 思路: 一眼看上去很像斯坦纳树 但是限制稍有不同,只要每种颜色的点联通即可 也就是说最 ...

  7. 洛谷P3261 [JLOI2015]城池攻占(左偏树)

    传送门 每一个城市代表的点开一个小根堆,把每一个骑士合并到它开始攻占的城池所代表的点上 然后开始dfs,每一次把子树里那些还活着的骑士合并上来 然后再考虑当前点的堆,一直pop直到骑士全死光或者剩下的 ...

  8. sscanf小技巧-洛谷P7911 网络连接

    sscanf小技巧-洛谷P7911 网络连接 序言 本题解来源:本蒟蒻上课摸鱼 (别学我) 最近学了一个挺好用的函数--sscanf(),结合洛谷P7911 网络连接讲一下. (点击查看题目) 推荐几 ...

  9. 洛谷P2763 试题库问题

    题目:https://www.luogu.org/problemnew/show/P2763 题目描述 «问题描述: 假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性. ...

  10. 洛谷P2766-最长递增子序列问题

    chunlvxiong的博客 题目描述: 给定正整数序列x1,...,xn (1≤n≤500). 1.计算其最长递增子序列的长度s. 2.计算从给定的序列中最多可取出多少个长度为s的递增子序列. 3. ...

最新文章

  1. Maven build标签
  2. Wireshark默认不抓取本地包的解决方式
  3. mysql修改编码格式6_修改编码格式MySQL
  4. Dynamics 365-关于Solution的那些事(一)
  5. VTK:Picking之HighlightSelection
  6. JS实现Unix时间戳(Unix timestamp)转换工具-toolfk程序员工具网
  7. C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):目录
  8. day31 java的多线程(1)
  9. cstring::replace不区分大小写_Excel VBA之函数篇-3.11订单号千奇百怪,如何按照结构区分来源...
  10. [CodeForces332E]Binary Key
  11. Springboot之GetMapping参数
  12. Atitit 团队工具链体系打造---提升团队效率的一些通用软件 attilax总结
  13. Smart View的客户化开发
  14. 令 Debian 支援中文
  15. XXX团队邮件工作制与日常工作原则V1.0
  16. 正态分布变换NDT算法原理及其在点云配准中的应用
  17. 奥运排行榜(25 分)
  18. LeetCode LCP 19 秋叶收藏集 HERODING的LeetCode之路
  19. 伊利成为澳优第一大股东;Interbrand 2021年全球最佳品牌榜可口可乐、麦当劳排名前十 | 食品饮料新品...
  20. 无人驾驶汽车背后的伦理困境

热门文章

  1. 木门怎么打_装门框,只打发泡剂一点不牢固!如今门套下沉,气得邻居直跺脚!...
  2. imageio.write页面怎么显示_微信吃喝玩乐怎么没有了?微信支付页面吃喝玩乐在哪里...
  3. Qt:利用telnet连接PMAC
  4. java 下载速度计算_测量Java下载速度
  5. Spark中的python shell交互界面Ipython和jupyter notebook
  6. 产品经理训练营:让正确的事情相继发生 开营直播
  7. 极客大学产品经理训练营 用例Use Case 第8课总结
  8. 极客大学架构师训练营 JVM虚拟机原理 JVM垃圾回收原理 Java编程优化 第17课 听课总结
  9. First Bad Version
  10. 375.猜数字大小II