zoukankan      html  css  js  c++  java
  • 求无向图中连通指定的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
  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/starve/p/13791039.html
Copyright © 2011-2022 走看看