斯坦纳树入门

概述

斯坦纳树用于解决最优化连通图问题。即选择权值和最小的边集,使某些关键点连通。
斯坦纳树使用状压DP,设状态f[i][S]表示结点i与关键点集合S连通的答案。(注:这个状态定义我理解了很久,查了很多博客,因为有些博客没有说清楚,什么“至少为S”、“以i为根”都不是很准确。S中一定含i吗?不一定。但这个答案肯定是包含了S到i的路径的)
有两种转移方式:
1.子集转移,f[i][S]=min{f[i][T]+f[i][S-T]},其中T是S的子集。注意这个转移有点问题,有可能f[i][T]和f[i][S-T]统计了相同的点,因此还需要第二种转移。
2.边转移,f[i][S]=min{f[j][S]+w(i,j)},j有边连向i。相当于从i先到j,再到S。
正确性?不是很懂。
于是我们就枚举集合进行转移1。每次枚举完一个集合,跑一遍dijkstra进行转移2。

memset(f, 0x3f, sizeof(f));
for(int i = 0; i < n; i++) f[i][1<<i] = 0; // 自己与自己相连无代价
for(int S = 1; S < (1<<n); S++) { // S != 0
    for(int T = (S-1)&S; T; T = (S-1)&S) // proper subset
        for(int i = 0; i < n; i++) f[i][S] = min(f[i][S], f[i][T]+f[i][S^T]);
    memset(dj, 0x3f, sizeof(dj));
    for(int i = 0; i < n; i++) if(f[i][S] != inf) Q.push((heap){dj[i]=0, i});
    dijkstra(S);
}

例题

游览计划 WC2008

给定一个网格图,每个点有一个代价,求权值和最小的点集使得代价为0的点连通。两个相邻的点都被选中即为连通。

斯坦纳树模板题。因为权在点上,因此转移1要改为f[i][S]=min{f[i][T]+f[i][S-T]-cost(i)}。
另有一些细节。

管道连接 Jloi2015

给定一个无向图,上面有p个关键点,它们分为c种颜色。求权值和最小的边集使得每种颜色的关键点连通。

g(C)表示颜色集合为C,其中每个颜色的关键点都连通的答案。转移有两种,从子集转移和用斯坦纳树计算。即g(C)=min{g(T)+g(C-T), steiner_tree(Vertex(C))}。子集转移相当于两棵树到一个森林的过程,因此不用加限制。

桃花源

给定一个无向图,求将前k个点与后k个点任意配对后,权值和最小的边集使得每对点连通。

g(S)表示关键点连通性集合为S的答案。同样有子集和斯坦纳树两种转移。子集转移的条件是集合都满足前面选的点数=后面选的点数。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值