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
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.