首页 > 其他分享 >最小斯坦纳树

最小斯坦纳树

时间:2022-10-25 11:02:22浏览次数:80  
标签:ch const int 最小 斯坦纳 转移

最小斯坦纳树

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

我们所熟知的最小生成树问题其实就是一种特殊的最小斯坦纳树问题,相当于在所有点之间找到一个最短网络

实现

luoguP3366 【模板】最小生成树

题目描述:
给定一个包含 \(n\) 个结点和 \(m\) 条带权边的无向连通图 \(G=(V,E)\)。
再给定包含 \(k\) 个结点的点集 \(S\),选出 \(G\) 的子图 \(G'=(V',E')\),使得:

  1. \(S\subseteq V'\);
  2. \(G'\) 为连通图
  3. \(E'\)中所有边的权值和最小

求出 \(E'\) 中所有边的权值和

我们通过状压dp求解最小斯坦纳树

由于处理的是一个树形结构,所以以树形为基础设计状态

设 f[i][S] 表示以 i 为根,当前选出的点集为 S

通过两个部分来转移,一是兄弟节点之间的转移,二是根节点之间的转移

兄弟节点之间的转移我们这样实现

\[ f[i][S] = min( f[i][S], f[i][T] + f[i][S-T] ); \]

其中 T 是 S 的子集,这个方程的意思就是将 i 的所有子树合并在一起

对于根节点之间的转移我们这样实现

\[f[i][S] = f[j][s] + w( i, j ) \]

即将子树 j 连接到新的根 i 上。
可以发现这个式子和我们最短路中的三角形不等式非常相像,所以只需要跑一个最短路转移即可

代码实现
#include <bits/stdc++.h>

#define ll long long
#define mod 1e9+7
const int MAXN = 101010;
const int inf = 2e9;

using namespace std;

struct edge{
    int u, v, w, nxt;
} e[MAXN];
struct node{
    int p, w;
    bool operator< ( const node x ) const{
        return w > x.w;
    }
};

int head[MAXN], cnt = 1;
int f[200][2048];
int dis[200], vis[200];
int n, m, k;
priority_queue < node > q;

inline int read( ){
    int x = 0 ; short w = 0 ; char ch = 0;
    while( !isdigit(ch) ) { w|=ch=='-';ch=getchar();}
    while( isdigit(ch) ) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return w ? -x : x;
}

void add( int u, int v, int w ){
    e[++cnt] = (edge){ u, v, w, head[u] };
    head[u] = cnt;
}

void dij( int s ){
    memset( vis, 0, sizeof( vis ) );
    for( int i = 1; i <= n; i++ ){
        dis[i] = f[i][s];
        if( dis[i] < inf ) q.push((node){i, dis[i]});
    }
    while( !q.empty( ) ){
        int x = q.top( ).p;
        q.pop( );
        if( vis[x] ) continue;
        vis[x] = 1;
        for( int i = head[x]; i; i = e[i].nxt ){
            int y = e[i].v;
            if( dis[x] + e[i].w < dis[y] ){
                dis[y] = dis[x] + e[i].w;
                q.push((node){y, dis[y]});
            }
        }
    }

    for( int i = 1; i <= n; i++ )
        f[i][s] = dis[i];
}

int main( ){
    
    memset( f, 0x3f, sizeof( f ) );

    n = read( ); m = read( ); k = read( );
    
    for( int i = 1; i <= m; i++ ){
        int x = read( ), y = read( ), z = read( );
        add( x, y, z );
        add( y, x, z );
    }
    
    for( int i = 1; i <= k; i++ ){
        int x = read( );
        f[x][1 << (i - 1)] = 0;
    }
    for( int i = 1; i <= n; i++ ) f[i][0] = 0;
    
    for( int s = 0; s < ( 1 << k ); s++ ){
        for( int i = 1; i <= n; i++ )
            for( int t = s & ( s - 1 ); t; t = s & ( t - 1 ) )
                f[i][s] = min( f[i][s], f[i][t] + f[i][t ^ s] );
        dij( s );
    }

    int ans = inf;

    for( int i = 1; i <= n; i++ )
        ans = min( ans, f[i][(1 << k) - 1] );

    cout << ans;

    return 0;
}

这里我用的dij,当然SPFA也可以但是慎用

标签:ch,const,int,最小,斯坦纳,转移
From: https://www.cnblogs.com/Lkkaknoi/p/16824154.html

相关文章

  • 858 Prim算法求最小生成树
    #include<bits/stdc++.h>usingnamespacestd;constintN=510,INF=0x3f3f3f3f;intn,m;intg[N][N];//储存边intdist[N];//储存点到集合的距离intst[N......
  • BZOJ 4519([Cqoi2016]不同的最小割-Gusfield算法)
    题意:给一幅图,问2点之间最小割有几个不同取值。1<=N<=8501<=M<=8500Gusfield算法如下:假设一开始所有点均在同一集合任意选定2个不在同一集合点求最小割,割把点集分成......
  • BZOJ 1797([Ahoi2009]Mincut 最小割-最小割的可行边与必行边)
    DescriptionA,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i(1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,......
  • 多个日期,找最大最小日期
    //最大最小日期privatestaticStringshowMaxDate(String[]dateArray){Map<String,Integer>dateMap=newTreeMap<String,Integer>();......
  • 最小化及关闭远程桌面后键盘与鼠标仍处于可交互状态
    默认情况下,当用户没有在Windows上执行任何输入(没有鼠标键盘等的输入)并保持一定时间后,Windows会自动切换到锁屏模式(或屏保模式),甚至待机。一般情况下,这样不会有任......
  • 0308 寻找文件夹中的最大和最小文件
    packageIO流;importjava.io.File;importjava.util.Date;importjava.io.FileInputStream;importjava.io.FileNotFoundException;/***@authorshawnwen*@version创......
  • python | 算法-最小生成树-prim算法
    写在前面:我自己用python练习算法与数据结构的典型算法汇总在这里:汇总-算法与数据结构-python版,欢迎翻阅!1️⃣参考链接:https://github.com/algorithmzuo/algorithmbasic......
  • c语言求最大公约数(c语言求最大公约数和最小公倍数代码)
    C语言中求两个数的最大公约数的公式是什么?inti,a=3,b=6;intmax=b;//初始化b大,下面判断如果a>b就把a给max//判断a,b大小if(a>b)max=a;for(i=max;i>0;i--)//公约数肯定不......
  • 最小生成树
    1.最小生成树定义:一个有n个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有n个结点,并且有保持图连通的最少的边。通俗易懂的讲就是最小生成树包含原图......
  • PriorityQueue 最小堆&& treemap
    优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素)。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(naturalorder......