zoukankan      html  css  js  c++  java
  • 【BZOJ】4349: 最小树形图

    题解

    我们只考虑给每个点买一个,之后每个点就可以用最低价格买了

    根据最小树形图的算法,就是不断给每个点入度的边找一条最小的

    如果构成了树形图就退出,否则把形成了环的点缩成一个点,加上环的权值,然后把指向环中点的弧变成弧长减去环中指向该点的弧的长度

    重标号让代码显得好难看啊QAQ

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 1000005
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
        }
        while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
        out(x / 10);
        }
        putchar('0' + x % 10);
    }
    int N,num[55],Ncnt,id[55];
    db g[55][55],f[55][55],ans,val[55],tmp,minv[55];
    int h[55][55],sta[55],top,low[55],dfn[55],idx,instack[55],tot;
    int que[55],qr;
    void Tarjan(int u) {
        low[u] = dfn[u] = ++idx;
        sta[++top] = u;
        instack[u] = 1;
        for(int v = 1 ; v < Ncnt ; ++v) {
            if(h[u][v]) {
                if(!dfn[v]) {Tarjan(v);low[u] = min(low[u],low[v]);}
                else if(instack[v] == 1) {low[u] = min(low[u],dfn[v]);}
            }
        }
        if(low[u] >= dfn[u]) {
            ++tot;
            qr = 0;
            while(1) {
                int x = sta[top--];
                id[x] = tot;
                que[++qr] = x;
                instack[x] = 2;
                if(x == u) break;
            }
            if(qr == 1) {val[que[1]] = 0;}
            else {
                for(int i = 1 ; i <= qr ; ++i) ans += val[que[i]];
            }
        }
    }
    void shortest_arborescence() {
        while(1) {
            memset(h,0,sizeof(h));
            tmp = 0.0;
            for(int i = 1 ; i < Ncnt ; ++i) {
                int t = Ncnt;
                for(int j = 1 ; j < Ncnt ; ++j) {
                    if(g[j][i] < g[t][i]) t = j;
                }
                h[t][i] = 1;
                val[i] = g[t][i];
                tmp += val[i];
            }
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(instack,0,sizeof(instack));
            tot = 0;idx = 0;top = 0;
            for(int i = 1 ; i < Ncnt ; ++i) {
                if(!dfn[i]) Tarjan(i);
            }
            id[Ncnt] = ++tot;
            if(tot == Ncnt) {
                ans += tmp;
                break;
            }
            for(int i = 1 ; i <= tot ; ++i) {
                for(int j = 1 ; j <= tot ; ++j) {
                    f[i][j] = 1000000000.0;
                }
            }
            for(int i = 1 ; i <= Ncnt ; ++i) {
                for(int j = 1 ; j <= Ncnt ; ++j) {
                    if(id[i] == id[j]) continue;
                    if(g[i][j] < 1000000000)
                        f[id[i]][id[j]] = min(f[id[i]][id[j]],g[i][j] - val[j]);
                }
            }
            Ncnt = tot;
            memcpy(g,f,sizeof(f));
        }
        printf("%.2lf
    ",ans);
    }
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N + 1 ; ++i) {
            for(int j = 1 ; j <= N + 1 ; ++j) {
                g[i][j] = 1000000000.0;
            }
        }
        for(int i = 1 ; i <= N ; ++i) {
            scanf("%lf",&minv[i]);
            read(num[i]);
            g[N + 1][i] = minv[i];
            if(num[i]) id[i] = ++Ncnt;
        }
        id[N + 1] = ++Ncnt;
        int k,A,B;db c;
        read(k);
        for(int i = 1 ; i <= k ; ++i) {
            read(A);read(B);scanf("%lf",&c);
            g[A][B] = min(g[A][B],c);
            if(num[A]) minv[B] = min(minv[B],c);
        }
        for(int i = 1 ; i <= N ; ++i) {
            if(num[i]) ans += minv[i] * (num[i] - 1);
        }
        for(int i = 1 ; i <= Ncnt ; ++i) {
            for(int j = 1 ; j <= Ncnt ; ++j) {
                f[i][j] = 1000000000.0;
            }
        }
        for(int i = 1 ; i <= N + 1; ++i) {
            if(!id[i]) continue;
            for(int j = 1 ; j <= N + 1; ++j) {
                if(!id[j]) continue;
                f[id[i]][id[j]] = g[i][j];
            }
        }
        memcpy(g,f,sizeof(g));
        shortest_arborescence();
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
  • 相关阅读:
    Vue中事件委托的使用
    java提取每个汉字的首字母
    想把大脑存进电脑,我为什么要写博客
    CF 1606 D题题解
    js前端 音频波形图像展示
    js前端 仪表盘实现
    js前端 bootstrap select的使用
    UOS系统维护命令
    linux 打印机管理常用命令
    linux 调用shell命令
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10073400.html
Copyright © 2011-2022 走看看