BZOJ3876:[AHOI2014]支线剧情

Description

【故事背景】
宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等。不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情。
这些游戏往往都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情。
【问题描述】
JYY现在所玩的RPG游戏中,一共有N个剧情点,由1到N编号,第i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点。当然如果为0,则说明i号剧情点是游戏的一个结局了。
JYY观看一个支线剧情需要一定的时间。JYY一开始处在1号剧情点,也就是游戏的开始。显然任何一个剧情点都是从1号剧情点可达的。此外,随着游戏的进行,剧情是不可逆的。所以游戏保证从任意剧情点出发,都不能再回到这个剧情点。由于JYY过度使用修改器,导致游戏的“存档”和“读档”功能损坏了,
所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到1号剧情点。JYY可以在任何时刻退出游戏并重新开始。不断开始新的游戏重复观看已经看过的剧情是很痛苦,JYY希望花费最少的时间,看完所有不同的支线剧情。

Input

输入一行包含一个正整数N。
接下来N行,第i行为i号剧情点的信息;
第一个整数为,接下来个整数对,Bij和Tij,表示从剧情点i可以前往剧
情点,并且观看这段支线剧情需要花费的时间。

Output

输出一行包含一个整数,表示JYY看完所有支线剧情所需要的最少时间。

Sample Input

6
2 2 1 3 2
2 4 3 5 4
2 5 5 6 6
0
0
0

Sample Output

24

HINT

对于100%的数据满足N<=300,0<=Ki<=50,1<=Tij<=300,Sigma(Ki)<=5000
 
题解:
这题有点类似BZOJ2324[ZJOI2011]营救皮卡丘,不过此题要求访问每一条边,而非每一个点。
将每个点i拆成i1与i2,增加i1——>i2的边,容量为inf,费用为0。
对于出度为x的拓扑节点i,增加x条i2——>T的边,容量为1,费用为对应出边的边权,表示这x条边都要被访问。
对于入度为x的节点i,增加1条S——>i1的边,容量为x,费用为0,表示这x条入边被访问后,都可以视为从该点重新出发。
对于点对(i,j),若i点可以到达j点,则增加i1——>j2的边,容量为inf,费用为距离,表示从i点出发走到j点,从而可以访问某个从j点引发的剧情。
设起点为R,添加一条S——>R1的边,容量为inf,费用为0,表示从起点出发。
这样建图后,跑一遍zkw费用流即可。
 
代码:
 1 var
 2   o,v:array[0..1600] of boolean;
 3   f,s,d,dis:array[0..1600] of longint;
 4   next,p,c,w:array[-100000..100000] of longint;
 5   i,j,k,l,y,t,tt,ft,n,ff,st,sf,ans,imp,new,flow:longint;
 6   a:array[0..301,0..301]of longint;
 7   tot:array[0..301]of longint;
 8 procedure link(i,j,k,l:longint);
 9 begin
10   inc(t);
11   next[t]:=d[i]; d[i]:=t; p[t]:=j; c[t]:=k; w[t]:=l;
12   next[-t]:=d[j]; d[j]:=-t; p[-t]:=i; w[-t]:=-l;
13 end;
14 function dfs(i,flow:longint):longint;
15 var j,k,l,min:longint;
16 begin
17   if i=tt then
18   begin
19     inc(ans,dis[i]*flow); exit(flow);
20   end;
21   k:=s[i]; j:=p[k]; dfs:=0;
22   o[i]:=true; v[i]:=true;
23   while k<>0 do
24   begin
25     l:=dis[i]+w[k]-dis[j]; min:=flow;
26     if c[k]<min then min:=c[k];
27     if(min>0)and(l<f[j])then f[j]:=l;
28     if(min>0)and(l=0)and(not o[j])then
29     begin
30       l:=dfs(j,min);
31       inc(dfs,l); dec(flow,l);
32       dec(c[k],l); inc(c[-k],l);
33     end;
34     if flow=0 then break;
35     s[i]:=next[s[i]];
36     k:=s[i]; j:=p[k];
37   end;
38   o[i]:=false;
39 end;
40 begin
41   readln(n); tt:=2*n+1;
42   for i:=1 to n do
43   for j:=1 to n do a[i,j]:=maxlongint div 2;
44   for i:=1 to n do
45   begin
46     read(k);
47     for j:=1 to k do
48     begin
49       read(l,y);
50       a[i,l]:=y; inc(tot[l]);
51       link(i,2*n+1,1,y);
52     end;
53   end;
54   for k:=1 to n do
55   for i:=1 to n do
56   for j:=1 to n do
57   if a[i,k]+a[k,j]<a[i,j] then a[i,j]:=a[i,k]+a[k,j];
58   for i:=1 to n do
59   for j:=1 to n do
60   if(i<>j)and(a[i,j]<maxlongint div 2)then
61   link(i+n,j,1 shl 20,a[i,j]);
62   link(0,1+n,1 shl 20,0);
63   for i:=1 to n do link(0,i+n,tot[i],0);
64   for i:=1 to n do link(i+n,i,1 shl 20,0);
65   repeat
66     for i:=0 to tt do s[i]:=d[i];
67     fillchar(v,sizeof(v),false);
68     fillchar(f,sizeof(f),1);
69     inc(flow,dfs(0,1 shl 20));
70     imp:=1 shl 20;
71     for i:=0 to tt do
72     if(not v[i])and(f[i]<imp)then imp:=f[i];
73     for i:=0 to tt do if not v[i] then inc(dis[i],imp);
74   until imp=1 shl 20;
75   writeln(ans);
76 end.
View Code
posted @ 2017-01-08 19:22  GhoStreach  阅读(257)  评论(0编辑  收藏  举报