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

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.萌新的总结

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

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

相关文章:

  • 2021-11-27
  • 2021-08-29
  • 2022-12-23
  • 2022-12-23
  • 2022-02-28
猜你喜欢
  • 2021-11-15
  • 2022-12-23
  • 2022-12-23
  • 2021-05-25
相关资源
相似解决方案