BZOJ 3876 支线剧情
支线剧情
【故事背景】
宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等。不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情。这些游戏往往都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情。
【问题描述】
JYY现在所玩的RPG游戏中,一共有N个剧情点,由1到N编号,第i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点。当然如果为0,则说明i号剧情点是游戏的一个结局了。
JYY观看一个支线剧情需要一定的时间。JYY一开始处在1号剧情点,也就是游戏的开始。显然任何一个剧情点都是从1号剧情点可达的。此外,随着游戏的进行,剧情是不可逆的。所以游戏保证从任意剧情点出发,都不能再回到这个剧情点。由于JYY过度使用修改器,导致游戏的“存档”和“读档”功能损坏了,
所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到1号剧情点。JYY可以在任何时刻退出游戏并重新开始。不断开始新的游戏重复观看已经看过的剧情是很痛苦,JYY希望花费最少的时间,看完所有不同的支线剧情。
【输入格式】
输入一行包含一个正整数N。
接下来N行,第i行为i号剧情点的信息;
第一个整数为,接下来个整数对,Bij和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次游戏,加上一开始的一次游戏,4次游戏的进程是
1->2->4,1->2->5,1->3->5和1->3->6。
对于100%的数据满足N<=300,0<=Ki<=50,1<=Tij<=300,Sigma(Ki)<=5000
题解:
题意就是要求走完所有边所需的最小时间(费用)
相当于有上下界无源汇可行最小费用流
那么就把题目中给定的边下界设为 1
重新开始就从每一个点连向点 1 就好了
具体见图可看代码
对于超级源与超级汇的连边也一起连在里面了
1 #include<cmath> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 const int maxn = 1e3 + 1; 9 const int maxm = 3e4 + 1; 10 const int inf = 1e9 + 7; 11 int n; 12 int s, t, nors, nort, sups, supt; 13 int du[maxn]; 14 int len; 15 int nex[maxm], fir[maxn], ver[maxm], con[maxm], val[maxm]; 16 bool vis[maxn]; 17 int que[maxm << 1], dis[maxn]; 18 int ans; 19 inline void Scan(int &x) 20 { 21 char c; 22 bool o = false; 23 while(!isdigit(c = getchar())) o = (c != '-') ? o : true; 24 x = c - '0'; 25 while(isdigit(c = getchar())) x = x * 10 + c - '0'; 26 if(o) x = -x; 27 } 28 inline void Add(int x, int y, int c, int w) 29 { 30 nex[++len] = fir[x]; 31 fir[x] = len; 32 ver[len] = y; 33 con[len] = c; 34 val[len] = w; 35 } 36 inline void Ins(int x, int y, int c, int w) 37 { 38 Add(x, y, c, w); 39 Add(y, x, 0, -w); 40 } 41 inline void Sup(int x, int y, int l, int r, int w) 42 { 43 if(l) du[x] -= l, du[y] += l; 44 if(l != r) Ins(x, y, r - l, w); 45 } 46 inline bool Spfa() 47 { 48 int head = 0, tail = 1; 49 for(int i = 1; i <= supt; ++i) 50 dis[i] = inf, vis[i] = false; 51 que[tail] = s; 52 dis[s] = 0; 53 vis[s] = true; 54 while(head < tail) 55 { 56 int u = que[++head]; 57 for(int i = fir[u]; i; i = nex[i]) 58 { 59 if(!con[i]) continue; 60 int v = ver[i]; 61 if(dis[v] > dis[u] + val[i]) 62 { 63 dis[v] = dis[u] + val[i]; 64 if(!vis[v]) 65 { 66 vis[v] = true; 67 que[++tail] = v; 68 } 69 } 70 } 71 vis[u] = false; 72 } 73 return dis[t] < inf; 74 } 75 int Dinic(int u, int f) 76 { 77 vis[u] = true; 78 if(u == t) return f; 79 int g = f; 80 for(int i = fir[u]; i; i = nex[i]) 81 { 82 if(!con[i]) continue; 83 int v = ver[i]; 84 if(vis[v] || dis[v] != dis[u] + val[i]) continue; 85 int h = Dinic(v, min(con[i], g)); 86 if(h) 87 { 88 con[i] -= h; 89 con[i ^ 1] += h; 90 g -= h; 91 ans += h * val[i]; 92 if(!g) return f; 93 } 94 } 95 return f - g; 96 } 97 inline int Flow(int x, int y) 98 { 99 s = x, t = y, ans = 0; 100 while(Spfa()) Dinic(s, inf); 101 return ans; 102 } 103 inline void Init() 104 { 105 len = 1; 106 nors = n << 1 | 1; 107 nort = nors + 1; 108 sups = nort + 1; 109 supt = sups + 1; 110 } 111 int main() 112 { 113 Scan(n); 114 int m, x, t; 115 Init(); 116 for(int i = 1; i <= n; ++i) 117 { 118 Scan(m); 119 Ins(i, supt, m, 0); 120 while(m--) 121 { 122 Scan(x), Scan(t); 123 Sup(i, x, 1, inf, t); 124 Ins(sups, x, 1, t); 125 } 126 if(i != 1) Ins(i, 1, inf, 0); 127 } 128 printf("%d", Flow(sups, supt)); 129 }