Description
JYY现在所玩的RPG游戏中,一共有N个剧情点,由
JYY观看一个支线剧情需要一定的时间。JYY一开始处在
所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到
Solution
还是先考虑上下界无源汇最小费用可行流。
一条u→v边权上下界为(w,L,R)的边,可以建超级源S′和超级汇T′,连S′→v边权上下界为(w,0,L)的边,连u→T′边权上下界为(0,0,L)的边,连u→v边权上下界为(w,0,R−L)的边。在这个图上跑最小费用最大流,若存在解的话,一定能在新建的边上跑满流。
而如果有源汇的话还是套路,连一条T→S边权上下界为(0,0,+∞)的边就好了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
const int INF = 0x3f3f3f3f;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0; int sgn = 0;
for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
if (sgn) x = -x;
}
struct edge {
int to, next, cap, cost;
edge (int t = 0, int n = 0, int ca = 0, int co = 0) {
to = t; next = n; cap = ca; cost = co;
}
};
edge G[N * N * 2];
int head[N];
int vis[N], dis[N], pre[N];
int Gcnt, n, m, x, y;
int S, T, SS, TT, ans;
queue<int> Q;
inline void AddEdge(int from, int to, int cap, int cost) {
G[++Gcnt] = edge(to, head[from], cap, cost); head[from] = Gcnt;
G[++Gcnt] = edge(from, head[to], 0, -cost); head[to] = Gcnt;
}
inline void Del(int u) {
for (int i = head[u]; i; i = G[i].next)
G[i].cap = G[i ^ 1].cap = 0;
}
inline bool SPFA(int S, int T) {
memset(dis, 0x3f, sizeof dis);
Q.push(S); vis[S] = true; dis[S] = 0;
while (!Q.empty()) {
x = Q.front(); Q.pop(); vis[x] = false;
for (int i = head[x]; i; i = G[i].next) {
edge &e = G[i];
if (e.cap && dis[x] + e.cost < dis[e.to]) {
dis[e.to] = dis[x] + e.cost;
pre[e.to] = i ^ 1;
if (!vis[e.to]) {
vis[e.to] = true;
Q.push(e.to);
}
}
}
}
return dis[T] != INF;
}
inline int Flow(int S, int T) {
int Cost = 0, f;
while (SPFA(S, T)) {
f = INF;
for (int i = T; i != S; i = G[pre[i]].to)
f = min(f, G[pre[i] ^ 1].cap);
for (int i = T; i != S; i = G[pre[i]].to) {
G[pre[i]].cap += f; G[pre[i] ^ 1].cap -= f;
}
Cost += f * dis[T];
}
return Cost;
}
int main(void) {
freopen("1.in", "r", stdin);
read(n); Gcnt = 1;
S = 1; T = n + 1; SS = n + 2; TT = n + 3;
for (int i = 1; i <= n; i++) {
read(m);
if (i != 1) AddEdge(i, T, INF, 0);
while (m--) {
read(x); read(y);
AddEdge(i, x, INF, y);
AddEdge(SS, x, 1, y);
AddEdge(i, TT, 1, 0);
}
}
AddEdge(T, S, INF, 0);
ans = Flow(SS, TT);
printf("%d\n", ans);
return 0;
}