• [题解][洛谷P6192]【模板】最小斯坦纳树


    斯坦纳树是一棵连接给定点集的树,其中边不一定在这些点里面连。
    可以使用 dp,设 (f_{i,S}) 表示 钦定 (i) 为根,连接了集合 (S) 的最小代价,转移分两种情况:
    (i) 度数为 (1),可以转移到和它相连的点 (j)
    (i) 度数不为 (1),可以由子集转移。
    第一种转移用最短路求即可。

    const int N=110,M=510;
    int n,m,k,ss[N];
    struct Edge {
      int to,nxt,w;
    }e[M<<1];
    int hd[N],cnt;
    il void ade(int u,int v,int w){
      e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=hd[u],hd[u]=cnt;
    }
    int f[N][2000];bool vis[N];
    queue<int> q;
    void SPFA(int S){
      memset(vis,0,sizeof vis);
      for(rg int i=1;i<=n;i++){
        if(f[i][S]!=INF)q.push(i),vis[i]=1;
      }
      while(!q.empty()){
        int u=q.front();q.pop(),vis[u]=0;
        for(rg int i=hd[u];i;i=e[i].nxt){
          int v=e[i].to;
          if(f[v][S]>f[u][S]+e[i].w){
            f[v][S]=f[u][S]+e[i].w;
            if(!vis[v])q.push(v),vis[v]=1;
          }
        }
      }
    }
    int main(){
      Read(n),Read(m),Read(k);
      for(rg int i=1,u,v,w;i<=m;i++){
        Read(u),Read(v),Read(w),ade(u,v,w),ade(v,u,w);
      }
      memset(f,0x3f,sizeof f);
      for(rg int i=1;i<=k;i++){
        Read(ss[i]);
        f[ss[i]][1<<i-1]=0;
      }
      for(rg int S=0;S<(1<<k);S++){
        for(rg int i=1;i<=n;i++){
          for(rg int T=S&(S-1);T;T=S&(T-1)){
            f[i][S]=min(f[i][S],f[i][T]+f[i][S^T]);
          }
        }
        SPFA(S);
      }
      cout<<f[ss[1]][(1<<k)-1]<<endl;
      KafuuChino HotoKokoa
    }
    
    内容来自_ajthreac_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
  • 相关阅读:
    简明 Vim 练级攻略
    设置命令的别名
    GPIO实验(二)
    GPIO实验(一)
    ubuntu文件夹默认列表显示
    ubuntu 12.04下gedit查看txt中文乱码解决办法
    ubuntu下超强的截图工具scrot
    原码 反码 补码 移码的关系(精简总结)
    内核编译
    [Linux] shell利用sed如何批量更改文件名详解[转载] | 不使用正则表达式,修改未知的文件名|
  • 原文地址:https://www.cnblogs.com/juruoajh/p/15392190.html
Copyright © 2020-2023  润新知