Description
给一张有向无环图,每次你可以选择一条从 (1) 号点出发的路径走,花费的时间为路径上边权的总和,问要使所有边都被走至少一遍,至少需要花费多久。
Solution
DAG 上的可重复定源路径覆盖,考虑有上下界网络流模型
对题意中的每个点建点,对于题意中的每条边,在建图时,费用为边权,容量下界为 (1),上界为 (+infty)
用 (1) 当源点,每个非源的点向 (T) 连边,容量不限制,费用为 (0)
在这个图上跑有源汇有上下界费用流
建立超级源点 (S') 和超级源点 (T'),对于所有原有点,对其下界,设 (d[p]=p) 的输入量 (- p) 的输出量,若 (d[p]>0) 则由 (S') 向 (p) 连边,费用为 (0),容量为 (|d[p]|);若 (d[p]<0) 则由 (p) 向 (T') 连边,,费用为 (0),容量为 (|d[p]|);否则不连边
原图中的汇点向原图中的源点连边,容量不限制,费用为 (0)
其它所有边的容量设为上界减去下界
在此基础上,跑最小费用最大流,得到的费用加上所有下界的费用就是答案
#include <bits/stdc++.h>
using namespace std;
#define int long long
// Init: init() !!!!!
// Input: make(u,v,cap,cost)
// Solver: solve(s,t)
// Output: ans, cost
const int inf = 1e+12;
namespace flow {
const int N = 100005;
const int M = 1000005;
struct Edge {
int p, c, w, nxt = -1;
} e[N];
int s, t, tans, ans, cost, ind, bus[N], qhead = 0, qtail = -1, qu[M],vis[N], dist[N];
void graph_link(int p, int q, int c, int w) {
e[ind].p = q;
e[ind].c = c;
e[ind].w = w;
e[ind].nxt = bus[p];
bus[p] = ind;
++ind;
}
void make(int p, int q, int c, int w) {
//cout<<p<<" "<<q<<" "<<c<<endl;
graph_link(p, q, c, w);
graph_link(q, p, 0, -w);
}
int dinic_spfa() {
qhead = 0;
qtail = -1;
memset(vis, 0x00, sizeof vis);
memset(dist, 0x3f, sizeof dist);
vis[s] = 1;
dist[s] = 0;
qu[++qtail] = s;
while (qtail >= qhead) {
int p = qu[qhead++];
vis[p] = 0;
for (int i = bus[p]; i != -1; i = e[i].nxt)
if (dist[e[i].p] > dist[p] + e[i].w && e[i].c > 0) {
dist[e[i].p] = dist[p] + e[i].w;
if (vis[e[i].p] == 0)
vis[e[i].p] = 1, qu[++qtail] = e[i].p;
}
}
return dist[t] < inf;
}
int dinic_dfs(int p, int lim) {
if (p == t)
return lim;
vis[p] = 1;
int ret = 0;
for (int i = bus[p]; i != -1; i = e[i].nxt) {
int q = e[i].p;
if (e[i].c > 0 && dist[q] == dist[p] + e[i].w && vis[q] == 0) {
int res = dinic_dfs(q, min(lim, e[i].c));
cost += res * e[i].w;
e[i].c -= res;
e[i ^ 1].c += res;
ret += res;
lim -= res;
if (lim == 0)
break;
}
}
return ret;
}
void solve(int _s,int _t) {
s=_s; t=_t;
while (dinic_spfa()) {
memset(vis, 0x00, sizeof vis);
ans += dinic_dfs(s, inf);
}
}
void init() {
memset(bus, 0xff, sizeof bus);
}
}
namespace limflow {
struct edge {
int u,v,l,r,c;
};
vector <edge> vec;
const int N = 100005;
int ans,cost,d[N];
void make(int u,int v,int l,int r,int c) {
vec.push_back({u,v,l,r,c});
}
void solve(int s,int t) {
ans=0;
cost=0;
flow::init();
int mx=0;
for(edge e:vec) {
mx=max(mx,max(e.u,e.v));
d[e.v]+=e.l;
d[e.u]-=e.l;
flow::make(e.u,e.v,e.r-e.l,e.c);
cost+=e.c*e.l;
}
flow::make(t,s,inf,0);
for(int i=1;i<=mx;i++) {
if(d[i]>0) {
flow::make(mx+1,i,abs(d[i]),0);
}
if(d[i]<0) {
flow::make(i,mx+2,abs(d[i]),0);
}
}
flow::solve(mx+1,mx+2);
ans=flow::ans;
cost+=flow::cost;
}
}
using limflow::make;
using limflow::solve;
using limflow::cost;
const int N = 100005;
int deg[N];
signed main() {
ios::sync_with_stdio(false);
int n,k,t1,t2;
cin>>n;
for(int i=1;i<=n;i++) {
cin>>k;
while(k--) {
cin>>t1>>t2;
deg[i]++;
make(i,t1,1,inf,t2);
}
}
for(int i=2;i<=n;i++) {
if(deg[i]==0) {
make(i,n+1,0,inf,0);
}
}
solve(1,n+1);
cout<<cost;
}