[题解] [JSOI2014] 支线剧情
题面
题解
很经典的上下界网络流模板题
每条边下界为 1 , 上界为 INF , 然后跑一遍最小费用可行流即可
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
const int N = 305;
const int M = 200005;
typedef long long ll;
const int INF = 0x3f3f3f3f;
using namespace std;
int n, S, T, s, t, k[N], c[N][N], b[N][N], d[N], head[N], cnt = 1, p[N];
ll ans, dis[N], a[N];
struct edge { int to, nxt; ll flow, cost; } e[M << 1];
bool vis[N];
queue<int> q;
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
inline void adde(int u, int v, int w, int c)
{
e[++cnt] = (edge) { v, head[u], w, c }, head[u] = cnt;
e[++cnt] = (edge) { u, head[v], 0, -c }, head[v] = cnt;
}
bool SPFA()
{
memset(dis, 0x3f, sizeof(dis)), memset(a, 0x3f, sizeof(a));
dis[s] = 0, q.push(s), vis[s] = 0;
while(!q.empty())
{
int u = q.front(); q.pop(); vis[u] = 0;
for(int v, i = head[u]; i; i = e[i].nxt)
{
v = e[i].to;
if(dis[v] > dis[u] + e[i].cost && e[i].flow)
{
dis[v] = dis[u] + e[i].cost, a[v] = min(a[u], e[i].flow);
p[v] = i; if(!vis[v]) vis[v] = 1, q.push(v);
}
}
}
if(dis[t] == dis[0]) return 0;
ans += a[t] * dis[t];
for(int i = t; i != s; i = e[p[i] ^ 1].to)
e[p[i]].flow -= a[t], e[p[i] ^ 1].flow += a[t];
return 1;
}
int main()
{
n = read <int> (), S = n + 1, T = S + 1, s = T + 1, t = s + 1;
for(int i = 1; i <= n; i++)
{
k[i] = read <int> ();
for(int j = 1; j <= k[i]; j++)
{
c[i][j] = read <int> (), b[i][j] = read <int> ();
d[c[i][j]]++, d[i]--, ans += b[i][j];
adde(i, c[i][j], INF, b[i][j]);
}
}
adde(S, 1, INF, 0);
for(int i = 1; i <= n; i++)
adde(i, T, INF, 0);
adde(T, S, INF, 0);
for(int i = 1; i <= n; i++)
if(d[i] < 0) adde(i, t, -d[i], 0);
else if(d[i] > 0) adde(s, i, d[i], 0);
while(SPFA());
printf("%lld\n", ans);
return 0;
}