zoukankan      html  css  js  c++  java
  • HDU 3311 Dig The Wells 【斯坦纳树:状压DP+SPFA】

    传送门

    题意

    可以在(n+m)个点上打井,可以修(p)条路,求前(n)个点能取到井水的最小花费是多少。

    题解

    把打井也转化为修路,即在(0)有一口井,然后求通过修路将(0,1,...,n)(n+1)个点连通的最小费用。
    如果是换成连通所有点的话,这个题就是一个最小生成树,可惜换不得。
    然而这个部分连通的最小花费也有对应的数据结构:斯坦纳树。这个题就是斯坦纳树的模板题。
    关于斯坦纳树的具体做法就不详细说了,就是状压DP+SPFA。

    代码

    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define pb push_back
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const double PI  = acos(-1.0);
    const double eps = 1e-8;
    const int inf = 0x3f3f3f3f;
    const LL INF  = 0x3f3f3f3f3f3f;
    const int N=1e4+10;
    const int M=5e4+10;
    const int mod=1e9+7;
    inline LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
    inline LL lcm(LL a, LL b) { return a * b / gcd(a, b); }
    inline LL read(){LL x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;}
    inline LL qpow(LL x,LL k=mod-2,LL m=mod){LL res=1;while(k){if(k&1) res=res*x%m;x=x*x%m;k>>=1;}return res;}
    /*=================================================================================================================*/
    int n,m,p,state[N];
    int head[N],to[M*2],nxt[M*2],val[M*2],tot;
    LL f[1010][100];
    void add(int u,int v,int w){
        to[++tot]=v;nxt[tot]=head[u];val[tot]=w;head[u]=tot;
    }
    queue<PII> que;
    int vis[1010][100];
    
    void spfa(){
        while(!que.empty()){
            int u=que.front().x,sta=que.front().y;
            vis[u][sta]=0;que.pop();
            for(int i=head[u];i;i=nxt[i]){
                int vsta=sta|state[to[i]];
                if(f[to[i]][vsta]>f[u][sta]+val[i]){
                    f[to[i]][vsta]=f[u][sta]+val[i];
                    if(!vis[to[i]][vsta]&&sta==vsta){
                        vis[to[i]][vsta]=1;
                        que.push({to[i],vsta});
                    }
                }
            }
        }
    }
    
    void Solve(){
        for(int i=0;i<=n+m;i++) head[i]=0;
        tot=0;
        for(int i=1,x;i<=n+m;i++){
            scanf("%d",&x);
            add(0,i,x);add(i,0,x);
        }
        for(int i=1,u,v,w;i<=p;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);add(v,u,w);
        }
        for(int i=0;i<=n+m;i++)for(int j=0;j<(1<<n+1);j++)f[i][j]=INF;
        for(int i=0;i<=n;i++)f[i][state[i]=1<<i]=0;
        for(int i=n+1;i<=m;i++) state[i]=0;
        for(int sta=0;sta<(1<<n+1);sta++){
            for(int i=0;i<=n+m;i++){
                //枚举子集
                for(int sub=sta&(sta-1);sub;sub=(sub-1)&sta)
                    f[i][sta]=min(f[i][sta],f[i][sub|state[i]]+f[i][sta-sub|state[i]]);
                if(f[i][sta]!=INF){
                    que.push({i,sta});
                    vis[i][sta]=1;
                }
            }
            spfa();
        }
        LL ans=INF;
        for(int i=0;i<=n+m;i++) ans=min(ans,f[i][(1<<n+1)-1]);
        printf("%lld
    ",ans);
    }
    
    int main(){
        while(~scanf("%d%d%d",&n,&m,&p)) Solve();
        
        return 0;
    }
    
    
  • 相关阅读:
    C++中关于文本内容的实用操作集合(新)(添加一些关于文件流的介绍)
    C++_String_类字符串操作(转)
    C++下面关于字符串数组的一些操作
    windows下 berkerly db的安装配置(修正了关键步骤)
    代码审计基础知识
    Spring中的依赖查找和依赖注入
    JavaSE实现IoC
    LeetCode 87. Scramble String
    LeetCode 76. Minimum Window Substring
    LeetCode 169. Majority Element
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/13645031.html
Copyright © 2011-2022 走看看