宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等。不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情。这些游戏往往都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情。
JYY现在所玩的RPG游戏中,一共有 N N N个剧情点,由 1 1 1到 N N N编号,第 i i i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点。当然如果为 0 0 0,则说明 i i i号剧情点是游戏的一个结局了。
JYY观看一个支线剧情需要一定的时间。JYY一开始处在 1 1 1号剧情点,也就是游戏的开始。显然任何一个剧情点都是从1号剧情点可达的。此外,随着游戏的进行,剧情是不可逆的。所以游戏保证从任意剧情点出发,都不能再回到这个剧情点。由于JYY过度使用修改器,导致游戏的“存档”和“读档”功能损坏了,
所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到 1 1 1号剧情点。JYY可以在任何时刻退出游戏并重新开始。不断开始新的游戏重复观看已经看过的剧情是很痛苦,JYY希望花费最少的时间,看完所有不同的支线剧情。
输入一行包含一个正整数N。
接下来 N N N行,第 i i i行为 i i i号剧情点的信息;
第一个整数为,接下来个整数对, B i j B_{ij} Bij和 T i j T_{ij} Tij,表示从剧情点i可以前往剧情点,并且观看这段支线剧情需要花费的时间。
输出一行包含一个整数,表示JYY看完所有支线剧情所需要的最少时间。
6
2 2 1 3 2
2 4 3 5 4
2 5 5 6 6
0
0
0
24
JYY需要重新开始 3 3 3次游戏,加上一开始的一次游戏, 4 4 4次游戏的进程是
样例解释
1->2->4,1->2->5,1->3->5和1->3->6。
对于100%的数据满足 N ≤ 300 , 0 ≤ K i ≤ 50 , 1 ≤ T i j ≤ 300 , S i g m a ( K i ) ≤ 5000 N\le 300,0\le K_i\le 50,1\le T_{ij}\le 300,Sigma(K_i)\le 5000 N≤300,0≤Ki≤50,1≤Tij≤300,Sigma(Ki)≤5000
每条边都要有至少为 1 1 1的流量, 并且要求费用最小, 就是带上下界的最小费用可行流, 那么强制每条边下界为 1 1 1, 跑最小费用最大流补流即可。
代码如下:
#include
#include
#include
#include
#include
#include
#include
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 305
#define INF 1e8
template <class C> IN C max(C a, C b) {return a > b ? a : b;}
template <class C> IN C min(C a, C b) {return a < b ? a : b;}
template <class C> IN void in(C &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int n, cnt, S, T, sum, TT;
int head[MX], dis[MX], del[MX], pre[MX], deg[MX];
bool inq[MX];
struct Edge {int to, fl, len, nex;} edge[200500];
IN void add(R int from, R int to, R int fl, R int len)
{
edge[++cnt] = {to, fl, len, head[from]}, head[from] = cnt;
edge[++cnt] = {from, 0, -len, head[to]}, head[to] = cnt;
}
namespace MCMF
{
std::queue <int> q;
IN bool SPFA()
{
std::memset(dis, 63, sizeof(dis));
dis[S] = 0; del[S] = INF; q.push(S); R int now;
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if (dis[edge[i].to] > dis[now] + edge[i].len && edge[i].fl)
{
dis[edge[i].to] = dis[now] + edge[i].len;
del[edge[i].to] = min(del[now], edge[i].fl);
pre[edge[i].to] = i;
if (!inq[edge[i].to]) inq[edge[i].to] = true, q.push(edge[i].to);
}
}
inq[now] = false;
}
return dis[T] ^ dis[0];
}
IN void update()
{
R int now = T, pr;
sum += del[T] * dis[T];
W (now ^ S)
{
pr = pre[now];
edge[pr].fl -= del[T], edge[pr ^ 1].fl += del[T];
now = edge[pr ^ 1].to;
}
}
IN void init()
{
W (SPFA()) update();
printf("%d", sum);
}
}
int main(void)
{
std::memset(head, cnt = -1, sizeof(head));
in(n); S = n + 1, TT = n + 2, T = n + 3;
int foo, a, b;
for (R int i = 1; i <= n; ++i)
{
in(foo);
for (R int j = 1; j <= foo; ++j)
{
in(a), in(b);
deg[i]--, deg[a]++; sum += b;
add(i, a, INF, b);
}
}
for (R int i = 2; i <= n; ++i) add(i, TT, INF, 0);
for (R int i = 1; i <= TT; ++i)
if (deg[i] > 0) add(S, i, deg[i], 0);
else add(i, T, -deg[i], 0);
add(TT, 1, INF, 0);
MCMF::init();
}