zoukankan      html  css  js  c++  java
  • ZOJ 3613 Wormhole Transport

    斯坦纳树,$dp$。

    先求出每个状态下连通的最小花费,因为可以是森林,所以$dp$一下。

    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    const int INF = 0x7FFFFFFF;
    struct X
    {
        int p,s,q;
    }e[210];
    int id[210];
    vector<int>g[210];
    int val[210][210],d[210][1200],dp[1200];
    int f[210*10000],k;
    queue<int>Q;
    
    int num[1200],cost[1200];
    
    void spfa()
    {
        while(!Q.empty())
        {
            int h = Q.front(); Q.pop(); f[h]=0;
            int x=h/10000,y=h%10000;
            for(int i=0;i<g[x].size();i++)
            {
                int to = g[x][i];
    
                if(to<k)
                {
                    if(((1<<to)&y)==0)
                    {
                        if(d[x][y]+val[x][to]<d[to][y|(1<<to)])
                            d[to][y|(1<<to)]=d[x][y]+val[x][to];
                    }
                }
    
                else
                {
                    if(d[x][y]+val[x][to]<d[to][y])
                    {
                        d[to][y] = d[x][y]+val[x][to];
                        if(f[to*10000+y]==0)
                        {
                            f[to*10000+y]=1;
                            Q.push(to*10000+y);
                        }
                    }
                }
            }
        }
    }
    
    bool cmp(X a,X b)
    {
        if(a.p!=b.p) return a.p>b.p;
        return a.s>b.s;
    }
    
    void work(int x)
    {
        int A=0,B=0;
        for(int i=0;i<k;i++)
        {
            if(((1<<i)&x)==0) continue;
            A=A+e[i].p; B=B+e[i].s;
        }
        num[x] = min(A,B);
        cost[x] = dp[x];
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            for(int i=0;i<n;i++)
            {
                scanf("%d%d",&e[i].p,&e[i].s);
                e[i].p = min(4,e[i].p);
                e[i].q = i;
            }
            sort(e,e+n,cmp);
            for(int i=0;i<n;i++) id[e[i].q]=i;
    
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++) val[i][j]=INF;
            memset(f,0,sizeof f);
            for(int i=0;i<n;i++) g[i].clear();
    
            int m; scanf("%d",&m);
            for(int i=1;i<=m;i++)
            {
                int a,b,c; scanf("%d%d%d",&a,&b,&c);
                a--; b--; a=id[a]; b=id[b];
                val[a][b]=min(val[a][b],c);
                val[b][a]=val[a][b];
                g[a].push_back(b);
                g[b].push_back(a);
            }
    
            k=0; for(int i=0;i<n;i++) if(e[i].p||e[i].s) k++;
    
            int st = 1<<k;
            for(int j=0;j<st;j++)
                for(int i=0;i<n;i++) d[i][j]=INF;
    
            for(int i=0;i<n;i++)
            {
                if(i<k) d[i][1<<i]=0;
                else d[i][0]=0;
            }
    
            for(int j=0;j<st;j++)
            {
                for(int i=0;i<n;i++)
                {
                    if(i<k)
                    {
                        if(((1<<i)&j)==0) continue;
                        for (int x = j; x; x = (x-1)&j)
                        {
                            int A=x ,B=j-A;
                            if(d[i][A|(1<<i)]!=INF&&d[i][B|(1<<i)]!=INF)
                                d[i][j] = min(d[i][j], d[i][A|(1<<i)]+d[i][B|(1<<i)]);
                        }
                    }
                    else
                    {
                        for (int x = j; x; x = (x-1)&j)
                        {
                            int A=x ,B=j-A;
                            if(d[i][A]!=INF&&d[i][B]!=INF)
                                d[i][j] = min(d[i][j], d[i][A]+d[i][B]);
                        }
                    }
                    if(d[i][j]!=INF) Q.push(i*10000+j);
                }
                spfa();
            }
    
            for(int j=0;j<st;j++)
            {
                dp[j]=INF;
                for(int i=0;i<n;i++) dp[j]=min(dp[j],d[i][j]);
            }
    
            memset(num,0,sizeof num);
            memset(cost,0,sizeof cost);
    
            for(int i=0;i<st;i++)
            {
                if(dp[i]!=INF) work(i);
                for (int x = i; x; x = (x-1)&i)
                {
                    int A=x, B=i-x;
                    if(num[A]+num[B]>num[i])
                    {
                        num[i] = num[A]+num[B];
                        cost[i] = cost[A]+cost[B];
                    }
                    else if(num[A]+num[B]==num[i])
                    {
                        if(cost[A]+cost[B]<cost[i])
                            cost[i] = cost[A]+cost[B];
                    }
                }
            }
    
            int ans1=0,ans2=999999999;
            for(int i=0;i<st;i++) ans1=max(ans1,num[i]);
            for(int i=0;i<st;i++)
            {
                if(num[i]!=ans1) continue;
                ans2=min(ans2,cost[i]);
            }
            printf("%d %d
    ",ans1,ans2);
    
        }
        return 0;
    }
  • 相关阅读:
    htnl类名命规范
    JAVA集合中泛型的原理本质简介
    java 泛型中的上界(extend)和下界(super)
    elasticsearch深度分页问题
    AOP组合使用切面和自定义注解
    G1垃圾回收器基本知识及原理解析
    MyBatisplus源码解析
    生产环境碰到系统CPU飙高和频繁GC,你要怎么排查?
    fullgc触发条件_记一次生产频繁出现 Full GC 的 GC日志图文详解
    JavaThreadContextLoader(线程上线文类加载器)总结
  • 原文地址:https://www.cnblogs.com/zufezzt/p/6639250.html
Copyright © 2011-2022 走看看