• 求无向图中连通指定的k个节点的最小代价(斯坦纳树)


    题:https://www.luogu.com.cn/problem/P6192

    题意:求最小斯坦纳树

    分析:答案一定是树,因为有环的话,可以删除成环边让答案更小;

       dp[i][s],表示以 i 为根,状态为s的最小代价,枚举子集和补集来dp,用最短路把每个S松弛一下

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define MP make_pair
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    typedef long long ll;
    const int mod=1e9+7;
    const int M=1e4+6;
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    int dp[102][M];
    struct qnode{
        int v;
        ll c;
        qnode(int _v=0,ll _c=0):v(_v),c(_c){}
        bool operator <(const qnode &r)const{
         return c>r.c;
        }
    };
    struct Edge{
        int v;
        ll cost;
        Edge(int _v=0,ll _cost=0):v(_v),cost(_cost){}
    };
    vector<Edge>E[M];
    bool vis[M];
    priority_queue<qnode>que;
    void Dij(int cursta){
        memset(vis,false,sizeof(vis));
        qnode tmp;
        while(!que.empty()){
            tmp=que.top();
            que.pop();
            int u=tmp.v;
            if(vis[u])continue;
                vis[u]=true;
            for(int i=0;i<E[u].size();i++){
                int v=E[tmp.v][i].v;
                int cost=E[u][i].cost;
                if(!vis[v]&&dp[v][cursta]>dp[u][cursta]+cost){
                    dp[v][cursta]=dp[u][cursta]+cost;
                    que.push(qnode(v,dp[v][cursta]));
                }
            }
        }
    }
    void addedge(int u,int v,ll w){
        E[u].push_back(Edge(v,w));
    }
    int p[M];
    int main(){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int u,v,w,i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        memset(dp,0x3f,sizeof(dp));
        int limit=dp[0][0];
        for(int i=1;i<=k;i++){
            scanf("%d",&p[i]);
            dp[p[i]][1<<(i-1)]=0;
        }
        for(int s=1;s<(1<<k);s++){
            for(int i=1;i<=n;i++){
                for(int sta=s&(s-1);sta;sta=s&(sta-1))///枚举子集
                    dp[i][s]=min(dp[i][s],dp[i][sta]+dp[i][s^sta]);
                if(dp[i][s]<limit)
                    que.push(qnode(i,dp[i][s]));
            }
            Dij(s);
        }
        printf("%d
    ",dp[p[1]][(1<<k)-1]);///因为是要连通起k个指定节点,所以每个dp[p[i]]都是最小的,所以随便取一个
        return 0;
    }
    View Code
  • 相关阅读:
    java代理模式 (转)
    android平台中编写jni模块的方法(1)
    android平台中编写jni模块的方法(2)
    Android AIDL——实现机制浅析
    android平台中编写jni模块的方法(3)
    Android AIDL使用详解
    android Launcher——拖放功能深入研究
    android 布局长度单位深入研究
    android Launcher——数据加载与变更
    PHP安装
  • 原文地址:https://www.cnblogs.com/starve/p/13791039.html
Copyright © 2020-2023  润新知