[AHOI2014/JSOI2014]支线剧情
有n个剧情点,对于第i个剧情点有ki个分支,分别通往tij剧情点,耗费时间为bij。从1号点开始,可以从任何节点返回1号点,要遍历所有的边的最少耗费时间为多少
上下界网络流板子题,每一条边的下界为1,除了起点外每一个点都可以是终点,所以建第n+1个点为汇点,这样就是一个有源有汇的上下界网络流,由汇点向源点建一条容量为inf的边。这个题没有上界,所以一定可以保证有可行流。
初始每条边都默认flow为1,先加入答案,然后建立平衡网络,跑出可行流加入答案即可。
//remember to delete freopen
#include <bits/stdc++.h>
using namespace std;
//faster_reader
inline int read ()
{
int f = 1, a = 0;
char c = getchar ();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar ();
}
while (c >= '0' && c <= '9')
{
a = a * 10 + c - '0';
c = getchar ();
}
return f * a;
}
const int N = 3100, M = 100010;
const int inf = 1e9 + 7;
long long ans = 0;
int head[N], now[N], num = -1;
int in[N], out[N], dis[N];
bool vis[N];
int s, t, n;
struct edge
{
int nxt, to, flow, pri;
};
edge e[M];
void addEdge(int x, int y, int z, int w)
{
e[++ num].nxt = head[x];
head[x] = num;
e[num].to = y;
e[num].flow = z;
e[num].pri = w;
}
bool spfa()
{
for (int i = 0; i <= n + 2; i ++)
dis[i] = inf;
dis[s] = 0;
queue <int> q;
q.push(s);
while (!q.empty())
{
int x = q.front(); q.pop();
for (int i = head[x]; i != -1; i = e[i].nxt)
{
int to = e[i].to;
if (dis[to] > dis[x] + e[i].pri && e[i].flow > 0)
{
dis[to] = dis[x] + e[i].pri;
q.push(to);
}
}
}
if (dis[t] != inf) return true;
return false;
}
int dfs(int x, int flow)
{
if (vis[x]) return 0;
vis[x] = 1;
if (x == t)
return flow;
for (int i = now[x]; i != -1; i = e[i].nxt)
{
now[x] = i;
int to = e[i].to;
if (dis[to] == dis[x] + e[i].pri && e[i].flow > 0)
{
int val = dfs(to, min(flow, e[i].flow));
if (val > 0)
{
e[i].flow -= val;
e[i ^ 1].flow += val;
ans += val * e[i].pri;
return val;
}
}
}
return 0;
}
void dinic(int x, int y)
{
s = x; t = y;
while (spfa())
{
for (int i = 0; i <= n + 2; i ++)
{
now[i] = head[i];
vis[i] = 0;
}
int val;
while (val = dfs (s, inf))
{
if (val == 0)
break;
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
n = read();
memset (head, -1, sizeof (head));
for (int i = 1; i <= n; i ++)
{
int k = read();
out[i] = k;
for (int j = 1; j <= k; j ++)
{
int tt, bb;
tt = read(); bb = read();
in[tt] ++;
ans += bb;
addEdge(i, tt, inf, bb);
addEdge(tt, i, 0, -bb);
}
if (i > 1)
{
addEdge(i, n + 1, inf, 0);
addEdge(n + 1, i, 0, 0);
}
}
addEdge(n + 1, 1, inf, 0);
addEdge(1, n + 1, 0, 0);
for (int i = 1; i <= n; i ++)
{
if (in[i] > out[i])
{
addEdge (0, i, in[i] - out[i], 0);
addEdge (i, 0, 0, 0);
}
if (in[i] < out[i])
{
addEdge (i, n + 2, out[i] - in[i], 0);
addEdge (n + 2, i, 0, 0);
}
}
s = 0; t = n + 2;
dinic(0, n + 2);
cout << ans;
return 0;
}