业界萌新对斯坦纳树的小结

0.简介

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

——百度百科

简单来讲,斯坦纳树问题一般就是给定一个n个点m条边的带非负权无向图,其中有k个关键点,要求选取一个子图,让所有关键点联通,而最小斯坦纳树则在斯坦纳树的前提下,让总费用最小

在此推荐一位学长的文章,写得很不错:详解斯坦纳点及斯坦纳树及模版归纳总结。

1.最小斯坦纳树的求解方法

斯坦纳树只要求k个关键点联通,显然不能够直接用最小生成树的方法解决。

  • 结论:最优解的方案一定会选取一棵树。
  • 证明:可行解显然是一个连通图,而如果图上存在一个环,费用为。我们可以将其中最长的一条边去掉,使得新费用,由于,所以。因此只会选取一棵树。

这样选取一棵树求最优解的问题,常见的思路是

2.具体实现

2.1状态

   表示以为根,关键点的选取状态为  的最优费用。

2.2转移

两重转移方程:

第一重转移,更新新的选取状态: , 

第二重转移,松弛新的选取状态:

由于之后的选取状态会由第一重转移更新,所以只需要对当前的选取状态进行松弛即可。

第一重转移直接,第二重转移用松弛

(PS:一般出题人不会在此处卡,但如果路遇毒瘤出题人黑心卡,还是用吧)。

时间复杂度显然:,c是的常数,E是边数。

2.3细节与技巧:

  • 倘若每一次都全图松弛会产生大量冗余运算,只需要对当前层节点进行松弛。
  • 子集枚举时可以用:   and表示位运算的与。

3.一个例题:[WC2008][luoguP4294]游览计划

题目描述

从未来过绍兴的小D有幸参加了Winter Camp 2008,他被这座历史名城的秀丽风景所吸引,强烈要求游览绍兴及其周边的所有景点。

主办者将绍兴划分为N行M列(N×M)个分块,如下图(8×8):

景点含于方块内,且一个方块至多有一个景点。无景点的方块视为路。

为了保证安全与便利,主办方依据路况和治安状况,在非景点的一些方块内安排不同数量的志愿者;在景点内聘请导游(导游不是志愿者)。在选择旅游方案时,保证任意两个景点之间,存在一条路径,在这条路径所经过的每一个方块都有志愿者或者该方块为景点。既能满足选手们游览的需要,又能够让志愿者的总数最少。

例如,在上面的例子中,在每个没有景点的方块中填入一个数字,表示控制该方块最少需要的志愿者数目:

图中用深色标出的方块区域就是一种可行的志愿者安排方案,一共需要20名志愿者。由图可见,两个相邻的景点是直接(有景点内的路)连通的(如沈园和八字桥)。

现在,希望你能够帮助主办方找到一种最好的安排方案。

输入输出格式

输入格式:

第一行有两个整数,N和M,描述方块的数目。

接下来N行,每行有M个非负整数,如果该整数为0,则该方块为一个景点;

否则表示控制该方块至少需要的志愿者数目。相邻的整数用(若干个)空格隔开,

行首行末也可能有多余的空格。

输出格式:

由N+1行组成。第一行为一个整数,表示你所给出的方案中安排的志愿者总数目。

接下来N行,每行M个字符,描述方案中相应方块的情况:

'_'(下划线)表示该方块没有安排志愿者;

'o'(小写英文字母o)表示该方块安排了志愿者;

'x'(小写英文字母x)表示该方块是一个景点;

注:请注意输出格式要求,如果缺少某一行或者某一行的字符数目和要求不一致(任何一行中,多余的空格都不允许出现),都可能导致该测试点不得分。

输入输出样例

输入样例#1:

4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0

输出样例#1:

6
xoox
___o
___o
xoox

说明

所有的 10 组数据中 N, M ,以及景点数 K 的范围规定如下

输入文件中的所有整数均不小于 0 且不超过 2^16

感谢@panda_2134 提供Special Judge

Solution

显然的最小斯坦纳树问题,  表示以这个格子为根,关键点选取状态为的最小个数。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=12;
const int MAXS=2005;
const int dx[4]={0,0,-1,1};
const int dy[4]={1,-1,0,0};
const int INF=0x3f3f3f3f;
int n,m,cnt,xt,yt;
int f[MAXN][MAXN][MAXS],c[MAXN][MAXN],p[MAXN][MAXN];
struct node{int x,y,s; } pre[MAXN][MAXN][MAXS];
bool ans[MAXN][MAXN],vis[MAXN][MAXN][MAXS];
queue<node> Q;
inline int read()
{int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }return x*f;
}
void find(int x,int y,int s)
{ans[x][y]=1;node q=pre[x][y][s];if (q.x==0) return;find(q.x,q.y,q.s);if (q.x==x&&q.y==y) find(x,y,(s-q.s)|p[x][y]);
}
void spfa()
{while (!Q.empty()){node q=Q.front(); Q.pop();int x=q.x,y=q.y,s=q.s;vis[x][y][s]=0;for (int i=0;i<4;i++){int xx=x+dx[i],yy=y+dy[i],ss=s|p[xx][yy];if (xx<1||xx>n||yy<1||yy>m) continue;if (f[x][y][s]+c[xx][yy]<f[xx][yy][ss]) {f[xx][yy][ss]=f[x][y][s]+c[xx][yy];pre[xx][yy][ss]=(node){x,y,s};if (s==ss&&(!vis[xx][yy][ss])) vis[xx][yy][ss]=1,Q.push((node){xx,yy,ss});}}}
}
int main()
{n=read(),m=read(),cnt=0;memset(f,INF,sizeof f);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){c[i][j]=read();if (!c[i][j]) p[i][j]=(1<<(cnt++)),xt=i,yt=j,f[i][j][p[i][j]]=0; }for (int S=1;S<(1<<cnt);S++){for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)if ((S&p[i][j]) || !p[i][j]){for (int s=(S-1)&S;s;s=(s-1)&S){int t=f[i][j][ (S-s)|p[i][j] ]+f[i][j][ s|p[i][j] ]-c[i][j]; //(i,j)这一点重复计算了,把c[i][j]消去。 if (f[i][j][S]>t) f[i][j][S]=t,pre[i][j][S]=(node){i,j,s|p[i][j]};//更新f[i][j][S],并记录路径。 }if (f[i][j][S]<INF) vis[i][j][S]=1,Q.push((node){i,j,S}); }spfa();}printf("%d\n",f[xt][yt][(1<<cnt)-1]);find(xt,yt,(1<<cnt)-1);for (int i=1;i<=n;i++){for (int j=1;j<=m;j++)if (p[i][j]) putchar('x');else if (ans[i][j]) putchar('o');else putchar('_');puts("");}return 0;
}

4.一些斯坦纳树题

[THUSC2017]巧克力 斯坦纳树+随机+二分

[BZOJ 4006] 管道连接

[hdu 3331]Trip the Lights Fantastic

[HDU 4085] Peach Blossom Spring

[ZOJ 3613] Wormhole Transport

5.萌新的总结

用状压解决最小斯坦纳树的时间复杂度对于是指数级别的,所以一般的最小斯坦纳数问题中,的范围在左右。

斯坦纳树实现并不难,思维难度也不高,还是一个很实用的算法。

业界萌新对斯坦纳树的小结相关推荐

  1. [APIO2013]机器人[搜索、斯坦纳树]

    题意 题目链接 分析 记 g(d,x,y) 表示从 (x,y) 出发,方向为 d 到达的点,这个可以通过记忆化搜索求出,注意如果转移成环(此时向这个方向走没有意义)要特判. 记 f(l,r,x,y) ...

  2. 斯坦纳树与旅行商问题

    啥也别说了,先上图 讨论了整整四个小时,只讨论了不到两章,我的那章还没讲完,真佩服我们.不过,印证了真理总是越辩越明这句话,通过这一次的讨论,对于我自己的那章,我都收获良多. 下面会写一下听第三章斯坦 ...

  3. 【算法竞赛学习笔记】超好懂的斯坦纳树详解!!!

    title : 斯坦纳树 tags : ACM 图论 date : 2021-6-26 author : Linno 什么是斯坦纳树 给定 n 个点 A1,A2,⋯,An试求连接此n个点,总长最短的直 ...

  4. hdu3311 Dig The Wells(斯坦纳树模板题)

    题目 n(1<=n<=5)个和尚,每个和尚位于一个寺庙内,标号1-n m(0<=m<=1e3)个其他地方,标号n+1到n+m 以下n+m个数,为在第i个地方打井所需的代价 以下 ...

  5. bzoj1402 Ticket to Ride 斯坦纳树 + 状压dp

    给定\(n\)个点,\(m\)条边的带权无向图 选出一些边,使得\(4\)对点之间可达,询问权值最小为多少 \(n \leqslant 30, m \leqslant 1000\) 首先看数据范围,\ ...

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

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

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

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

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

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

  9. 【BZOJ4774】修路 [斯坦纳树]

    修路 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output 仅一行一个整数表示答案. Sample Input 5 5 2 ...

最新文章

  1. java printwriter format_Java的格式化输出
  2. Kafka与RabbitMQ
  3. 解决Clover在win 10下的兼容问题
  4. 用ul和li实现表格table效果 (转)
  5. Lucene下载及测试
  6. matlab程序怎么改,修改matlab程序
  7. QT5+android_ubuntu软件源
  8. SAP ABAP实用技巧介绍系列之 关于View framework处理Before save event的讨论
  9. CSS基本布局16例
  10. gdi和gdi+并用
  11. Mini 容器学习笔记10——方法注入
  12. arcgis数据量大显示慢_优化MapGIS地图显示速度我的七个方法
  13. picasa csdn_使用Picasa网络相册开发PHP应用程序
  14. Excel中行数据转换为Java对象
  15. ubuntu修改桌面主文件夹为英文
  16. Python 3.6 中使用pdfminer解析pdf文件
  17. UGUI ContentSizeFitter 嵌套 适配
  18. CCM色彩调试黄色块饱和度不够
  19. 小程序开发--表格table的实现
  20. Zynga欲收购风靡全球的画画猜字游戏Draw Something

热门文章

  1. 研究表明:胸部大小其实早已.....
  2. 头上有多少根头发算秃头?
  3. linux 编写脚本示范,Linux-scripts-简单脚本和脚本的执行
  4. 5单个编译总会编译全部_VS2019 v16.5 MSVC编译器后端更新汇总
  5. php分目录存放session,phpsession实现多级目录存放实现代码,phpsession_PHP教程
  6. 金蝶凭证序时簿在哪_来了!金蝶日常账务处理大全
  7. javascript内存泄漏调试工具mac_node.js 内存泄漏的秘密
  8. Java当中捕获异常
  9. python编程中的小问题汇总
  10. linux 启动程序 绑定id,linux如何根据进程ID查找启动程序的路径