首页 > 代码库 > BZOJ3876[AHOI2014]支线剧情

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费用流即可。
 
代码:
技术分享
var
  o,v:array[0..1600] of boolean;
  f,s,d,dis:array[0..1600] of longint;
  next,p,c,w:array[-100000..100000] of longint;
  i,j,k,l,y,t,tt,ft,n,ff,st,sf,ans,imp,new,flow:longint;
  a:array[0..301,0..301]of longint;
  tot:array[0..301]of longint;
procedure link(i,j,k,l:longint);
begin
  inc(t);
  next[t]:=d[i]; d[i]:=t; p[t]:=j; c[t]:=k; w[t]:=l;
  next[-t]:=d[j]; d[j]:=-t; p[-t]:=i; w[-t]:=-l;
end;
function dfs(i,flow:longint):longint;
var j,k,l,min:longint;
begin
  if i=tt then
  begin
    inc(ans,dis[i]*flow); exit(flow);
  end;
  k:=s[i]; j:=p[k]; dfs:=0;
  o[i]:=true; v[i]:=true;
  while k<>0 do
  begin
    l:=dis[i]+w[k]-dis[j]; min:=flow;
    if c[k]<min then min:=c[k];
    if(min>0)and(l<f[j])then f[j]:=l;
    if(min>0)and(l=0)and(not o[j])then
    begin
      l:=dfs(j,min);
      inc(dfs,l); dec(flow,l);
      dec(c[k],l); inc(c[-k],l);
    end;
    if flow=0 then break;
    s[i]:=next[s[i]];
    k:=s[i]; j:=p[k];
  end;
  o[i]:=false;
end;
begin
  readln(n); tt:=2*n+1;
  for i:=1 to n do
  for j:=1 to n do a[i,j]:=maxlongint div 2;
  for i:=1 to n do
  begin
    read(k);
    for j:=1 to k do
    begin
      read(l,y);
      a[i,l]:=y; inc(tot[l]);
      link(i,2*n+1,1,y);
    end;
  end;
  for k:=1 to n do
  for i:=1 to n do
  for j:=1 to n do
  if a[i,k]+a[k,j]<a[i,j] then a[i,j]:=a[i,k]+a[k,j];
  for i:=1 to n do
  for j:=1 to n do
  if(i<>j)and(a[i,j]<maxlongint div 2)then
  link(i+n,j,1 shl 20,a[i,j]);
  link(0,1+n,1 shl 20,0);
  for i:=1 to n do link(0,i+n,tot[i],0);
  for i:=1 to n do link(i+n,i,1 shl 20,0);
  repeat
    for i:=0 to tt do s[i]:=d[i];
    fillchar(v,sizeof(v),false);
    fillchar(f,sizeof(f),1);
    inc(flow,dfs(0,1 shl 20));
    imp:=1 shl 20;
    for i:=0 to tt do
    if(not v[i])and(f[i]<imp)then imp:=f[i];
    for i:=0 to tt do if not v[i] then inc(dis[i],imp);
  until imp=1 shl 20;
  writeln(ans);
end.
View Code

BZOJ3876[AHOI2014]支线剧情