斯坦那树

百度释义

斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种。最小生成树是在给定的点集和边中寻求最短网络使所有点连通。而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小。

即最小斯坦那树即为并非选择所有的结点,而是选择一部分结点,为保证它们连通,且求解最小开销

题解

斯坦那树模板

发现直接表示点的存在性没有意义

设函数 \(f[i][state]\) 表示:对于点 \(i\),其它结点与其连通情况

那么有两种转移

其一、由其子集转移

\[f[i][state] = \min\limits_{sub \in state} \{f[i][sub] + f[i][\complement_{state}sub] - value_i\}
\]

之所以要减去 \(value_i\) 是因为会算重

附:枚举子集的方法

for (int sub = state & (state - 1); sub; sub = (sub - 1) & state)

其二、由相邻当前状态下结点转移

\[f[i][state] = \min\limits_{state_p = true} \{f[p][state] + value_i\}
\]

发现很像三角形不等式,故考虑 \(SPFA\) 转移

总复杂度 \(O (n3^n + kE2^n)\),\(3^n\) 为枚举子集总复杂度

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue> using namespace std; const int MAXN = 10 + 5;
const int MAXM = 1 << 10; const int INF = 0x3f3f3f3f; const int NextX[4]= {- 1, 0, 0, 1}, NextY[4]= {0, - 1, 1, 0}; int N, M;
int Map[MAXN][MAXN]= {0}; struct preSt {
int x, y;
int state; preSt (int fx = 0, int fy = 0, int fs = 0) :
x (fx), y (fy), state (fs) {}
} ; int f[MAXN][MAXN][MAXM];
preSt pre[MAXN][MAXN][MAXM];
int cnt = 0; queue<pair<int, int> > que;
void SPFA (int state) {
while (! que.empty()) {
pair<int, int> top = que.front();
que.pop(); int x = top.first, y = top.second;
for (int i = 0; i < 4; i ++) {
int tx = x + NextX[i];
int ty = y + NextY[i];
if (tx < 1 || tx > N || ty < 1 || ty > M)
continue;
if (f[x][y][state] + Map[tx][ty] < f[tx][ty][state]) {
f[tx][ty][state] = f[x][y][state] + Map[tx][ty];
pre[tx][ty][state] = preSt (x, y, state);
que.push(make_pair (tx, ty));
}
}
}
} int tag[MAXN][MAXN]= {0};
void traceback (int x, int y, int state) {
if (! x || ! y)
return ;
tag[x][y] = 1;
preSt pr = pre[x][y][state];
traceback (pr.x, pr.y, pr.state);
if (pr.x == x && pr.y == y)
traceback (pr.x, pr.y, state - pr.state);
} int getnum () {
int num = 0;
char ch = getchar (); while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << 3) + (num << 1) + ch - '0', ch = getchar (); return num;
} int main () {
memset (f, 0x3f, sizeof (f));
N = getnum (), M = getnum ();
int px, py;
for (int i = 1; i <= N; i ++)
for (int j = 1; j <= M; j ++) {
Map[i][j] = getnum ();
if (! Map[i][j]) {
cnt ++, f[i][j][1 << (cnt - 1)] = 0;
px = i, py = j;
}
}
int limit = (1 << cnt) - 1;
for (int state = 1; state <= limit; state ++) {
for (int i = 1; i <= N; i ++)
for (int j = 1; j <= M; j ++) {
for (int sub = state & (state - 1); sub; sub = (sub - 1) & state) // from subset
if (f[i][j][sub] + f[i][j][state - sub] - Map[i][j] < f[i][j][state]) {
f[i][j][state] = f[i][j][sub] + f[i][j][state - sub] - Map[i][j];
pre[i][j][state] = preSt (i, j, sub);
}
if (f[i][j][state] < INF)
que.push(make_pair (i, j));
}
SPFA (state); // from other nodes
}
traceback (px, py, limit);
printf ("%d\n", f[px][py][limit]);
for (int i = 1; i <= N; i ++) {
for (int j = 1; j <= M; j ++) {
if (! Map[i][j])
putchar ('x');
else {
tag[i][j] ? putchar ('o') : putchar ('_');
}
}
puts ("");
} return 0;
} /*
4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
*/

[WC2008]游览计划 「斯坦那树模板」的更多相关文章

  1. BZOJ_2595_[Wc2008]游览计划_斯坦纳树

    BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...

  2. BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*

    BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...

  3. 【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)

    上个月写的题qwq--突然想写篇博客 题目: 洛谷4294 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...

  4. bzoj 2595 [Wc2008]游览计划(斯坦纳树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题意] 给定N*M的长方形,选最少权值和的格子使得要求的K个点连通. [科普] ...

  5. BZOJ2595 WC2008游览计划(斯坦纳树)

    斯坦纳树板子题. 考虑状压dp,设f[i][j][S]表示当前在点(i,j)考虑转移,其所在的联通块包含的关键点集(至少)为S的答案. 转移时首先枚举子集,有f[i][j][S]=min{f[i][j ...

  6. [WC2008]游览计划(斯坦纳树)

    [Luogu4294] 题解 : 斯坦纳树 \(dp[i][j]\) 表示以\(i\)号节点为根,当前状态为\(j\)(与\(i\)连通的点为\(1\)) 当根\(i\)不改变时状态转移方程是: \( ...

  7. BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)

    题目链接 f[i][s]表示以i为根节点,当前关键点的连通状态为s(每个点是否已与i连通)时的最优解.i是枚举得到的根节点,有了根节点就容易DP了. 那么i为根节点时,其状态s的更新为 \(f[i][ ...

  8. 【BZOJ2595】[Wc2008]游览计划 斯坦纳树

    [BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为 ...

  9. 【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)

    2595: [Wc2008]游览计划 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1572  Solved: 7 ...

随机推荐

  1. Alpha 冲刺六

    团队成员 051601135 岳冠宇 051604103 陈思孝 031602629 刘意晗 031602248 郑智文 031602234 王淇 会议照片 今天没有进行站立式会议,由于团队内有些细节 ...

  2. idea打jar包没有MANIFEST文件坑

    看到横线处没有,将此处的main\java 删除掉 meta-inf文件夹必须在src文件夹下,才能打包成功, idea自动加了 main/java 会导致打包时,找不到该manifest文件,不会将 ...

  3. Linux命令(十四) 查看工作目录文件 ls

    目录 1.命令简介 2.常用参数介绍 3.实例 4.直达底部 命令简介 ls 命令是 Linux 下最常用的命令. ls 就是 list 的缩写.默认情况下 ls 命令用来打印出当前目录的清单, 如果 ...

  4. 服务端增加WCF服务全局异常处理机制

    服务端增加WCF服务全局异常处理机制,任一WCF服务或接口方式出现异常,将统一调用WCF_ExceptionHandler.ProvideFault方法,因此不需要每个方法使用try catch写法. ...

  5. java虚拟机的内存划分

    为了提高运算效率,就对空间进行不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式. 一. 1.jvm的内存划分: 区域名称 作用 寄存器 给cpu使用,和我们开发无关 本地方法栈 jv ...

  6. MT【82】凸函数

    评:对于(3)几何上来看要满足性质$P$图像来看必须下凸.这样区间中点$x=2$处不可能为最大.(4)的形式让我想起在证明算术几何平均不等式时历史上著名的柯西反向归纳证明:

  7. 洛谷P4219 [BJOI2014]大融合(LCT)

    LCT维护子树信息的思路总结与其它问题详见我的LCT总结 思路分析 动态连边,LCT题目跑不了了.然而这题又有点奇特的地方. 我们分析一下,查询操作就是要让我们求出砍断这条边后,x和y各自子树大小的乘 ...

  8. BZOJ 4380 [POI2015]Myjnie | DP

    链接 BZOJ 4380 题面 有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]. 有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个 ...

  9. BZOJ 4873 [Shoi2017]寿司餐厅 | 网络流 最大权闭合子图

    链接 BZOJ 4873 题解 当年的省选题--还记得蒟蒻的我Day1 20分滚粗-- 这道题是个最大权闭合子图的套路题.严重怀疑出题人就是先画好了图然后照着图编了个3000字的题面.和我喜欢的妹子当 ...

  10. bzoj1345 序列问题 (贪心)

    考虑某个点产生的贡献: 如果i左边是一个比它小的数x,那有两种情况: 1.x的左边的数y大于i,肯定要把x合并到i,i的贡献++ 2.x的左边的数y小于i,那肯定要把x合并到y,而这时候递归地来考虑, ...