【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('\n')
#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\n",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;
}
posted @ 2018-12-05 21:02  sigongzi  阅读(268)  评论(0编辑  收藏  举报