【BZOJ】4349: 最小樹形圖
阿新 • • 發佈:2018-12-05
題解
我們只考慮給每個點買一個,之後每個點就可以用最低價格買了
根據最小樹形圖的演算法,就是不斷給每個點入度的邊找一條最小的
如果構成了樹形圖就退出,否則把形成了環的點縮成一個點,加上環的權值,然後把指向環中點的弧變成弧長減去環中指向該點的弧的長度
重標號讓程式碼顯得好難看啊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; }