zoukankan      html  css  js  c++  java
  • 斯坦纳树

    斯坦纳树问题大概是这样一个问题:给定平面上 (n) 个点,然后求把这些点连起来的最短路径是多长,点有点权。

    如果放在 OI 上,那么就可以变成这样一个问题,给定一张联通的无向图,给定 (k) 个关键点,问把这 (k) 个关键点联通的边权和最小是多少,边有边权。

    解决方法

    我们设计一个状压 dp,(f_{i,s}) 表示目前包含关键点的集合为 (k),目前这颗树的根为 (i),有两种转移:

    • (f_{i,s}:=min(f_{i,s},f_{i,sub}+f_{i,overline{sub}}))
    • (f_{i,s}:=min(f_{i,s},f_{j,s}+w(i,j)))

    当然后者得保证 (i,j) 联通。

    第一个不难转移,我们首先枚举 (s),在枚举根,然后枚举子集转移即可。

    第二个转移很像最短路,我们不妨以状态作为其实点跑迪杰斯特拉来做最短路,我们采用优先队列,用优的去更新劣的,正确性显然。

    这个代码只是一个最初始的代码,有一些毒瘤题目需要卡常才能过。

    例题

    模板题

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    // #define int long long
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 510
    #define M 5010
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    template<typename T> inline T Min(T a,T b){return a<b?a:b;}
    
    struct node{
        int val,id;
        inline node(){}
        inline node(int val,int id) : val(val),id(id) {}
        inline bool operator < (const node &b)const{
            if(val!=b.val) return val>b.val;
            return id>b.id;
        }
    };
    priority_queue<node> q;
    
    struct edge{
        int to,next,w;
        inline void Init(int to_,int ne_,int w_){
            to=to_;next=ne_;w=w_;
        }
    }li[N<<1];
    int head[N<<1],tail;
    
    inline void Add(int from,int to,int w){
        li[++tail].Init(to,head[from],w);
        head[from]=tail;
    }
    
    int n,m,k,a[N],f[N][M<<1];
    
    inline void Init(){
        read(n);read(m);read(k);
        for(int i=1;i<=m;i++){
            int from,to,w;read(from);read(to);read(w);
            Add(from,to,w);Add(to,from,w);
        }
        memset(f,INF,sizeof(f));
        for(int i=1;i<=k;i++){
            read(a[i]);f[a[i]][1<<(i-1)]=0;
        }
    }
    
    bool vis[N];
    inline void dij(int s){
        memset(vis,0,sizeof(vis));
        while(q.size()){
            node top=q.top();q.pop();
            if(vis[top.id]) continue;
            vis[top.id]=1;
            for(int x=head[top.id];x;x=li[x].next){
                int to=li[x].to,w=li[x].w;
                if(f[to][s]<f[top.id][s]+w) continue;
                f[to][s]=f[top.id][s]+w;
                q.push(node(f[to][s],to));
            }
        }
    }
    
    inline void Dp(){
        for(int s=1;s<=(1<<k)-1;s++){
            for(int i=1;i<=n;i++){
                for(int sub=s&(s-1);sub;sub=s&(sub-1)){
                    f[i][s]=Min(f[i][s],f[i][sub]+f[i][s^sub]);
                }
                if(f[i][s]!=INF) q.push(node(f[i][s],i));
                vis[i]=0;
                // printf("before:f[%d][%d]=%d
    ",i,s,f[i][s]);
            }
            dij(s);
            // for(int i=1;i<=n;i++){
            //     printf("f[%d][%d]=%d
    ",i,s,f[i][s]);
            // }
        }
        printf("%d
    ",f[a[1]][(1<<k)-1]);
    }
    
    signed main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        Init();Dp();
    }
    /*
    6781325
    */
    
  • 相关阅读:
    PTP 接线方式及通讯距离
    串口通信基本概念
    Modbus RTU 通信应用案例
    Modbus 指令
    Modbus RTU新版本指令介绍
    Integer自动装箱和拆箱
    重写hashCode方法,导致内存泄漏
    Dom4j入门
    Java设计模式(9)——观察者模式
    IntelliJ IDEA版本控制——过滤提交文件
  • 原文地址:https://www.cnblogs.com/TianMeng-hyl/p/15404172.html
Copyright © 2011-2022 走看看