斯坦那树

百度释义

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

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

题解

斯坦那树模板

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

设函数 \(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. Spark 实践——基于 Spark Streaming 的实时日志分析系统

    本文基于<Spark 最佳实践>第6章 Spark 流式计算. 我们知道网站用户访问流量是不间断的,基于网站的访问日志,即 Web log 分析是典型的流式实时计算应用场景.比如百度统计, ...

  2. c#代码阅读

    问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间精确到分钟(电脑:单核CPU 4 ...

  3. appearance格式化表单元素的边框,在chrome和FF下鼠标点击时会多出一个蓝色边框

    可在元素上添加样式 -webkit-appearance: none; -moz-appearance:none;outline:none; 清除掉元素所有的外貌,以便自定义风格

  4. JAVA面对对象(一)——封装

    1.封装思想:将对象的属性和行为封装起来的载体是类,类通常对客户隐藏其实现的细节 2.封装就是将属性私有化(private),并提供公共的方法(public)访问私有属性 3.通过封装,实现对属性数据 ...

  5. 『编程题全队』Alpha 阶段冲刺博客Day5

    1.每日站立式会议 1.会议照片 2.昨天已完成的工作统计 孙志威: 1.完成SlotWidget的设计和功能 2.修改了TitleBar上的功能按钮的CSS样式表 孙慧君: 1.登录框的UI设计 2 ...

  6. ehcache、redis应用场景比较

    应用场景: ehcache是Hibernate中默认的CacheProvider,直接在jvm虚拟机中缓存,速度快,效率高:但是缓存共享麻烦,集群分布式应用不方便.  . 缓存数据有两级:内存和磁盘, ...

  7. springMVC返回给页面参数的三种形式

  8. Linux Deploy Ubuntu安装MySQL

    一.在Android手机安装Linux 二.Ubuntu安装Mysql 建议在root用户上操作 sudo su 输入密码 (一)安装mysql 1. sudo apt-get install mys ...

  9. Triangle Counting UVA - 11401(递推)

    大白书讲的很好.. #include <iostream> #include <cstring> using namespace std; typedef long long ...

  10. Django_重装系统后无法使用 sqlite 数据库报错:com.intellij.execution.ExecutionException: Exception in thread "main" java.lang.ClassNotFoundException: org.sqlite.JDBC

     重装系统后无法使用 sqlite 数据库报错 报错 : com.intellij.execution.ExecutionException: Exception in thread "ma ...