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
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
Solution
有上下界有源汇费用流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int N=350,M=60000; int n,degree[N]; namespace MinCostFlow { int tot,S,T,Next[M],head[N],tree[M],val[M],Cost[M],From[M],Prev[N],FLOW,dis[N],Queue[N*2]; bool visit[N]; void add(int x,int y,int z,int d) { tot++; Next[tot]=head[x]; head[x]=tot; tree[tot]=y; val[tot]=z; Cost[tot]=d; From[tot]=x; } void add_edge(int x,int y,int z,int d) { add(x,y,z,d); add(y,x,0,-d); } bool spfa() { memset(visit,0,sizeof(visit)); memset(Prev,0,sizeof(Prev)); for (int i=1;i<=T;i++) dis[i]=1<<29; int t=0,w=1; Queue[1]=S;visit[S]=1; dis[S]=0; while (t!=w) { t++; if (t>T*2) t=1; int u=Queue[t]; if (u==T) continue; visit[u]=0; for (int i=head[u];i;i=Next[i]) if (val[i]>0) { int v=tree[i]; if (dis[v]>dis[u]+Cost[i]) { dis[v]=dis[u]+Cost[i]; Prev[v]=i; if (!visit[v]) { w++; if (w>T*2) w=1; Queue[w]=v; visit[v]=1; } } } } return Prev[T]!=0; } int GetAns() { int Flow=1<<29,ans=0; for (int i=T;Prev[i];i=From[Prev[i]]) Flow=min(val[Prev[i]],Flow); FLOW+=Flow; for (int i=T;Prev[i];i=From[Prev[i]]) { ans+=Cost[Prev[i]]*Flow; val[Prev[i]]-=Flow; val[Prev[i]^1]+=Flow; } return ans; } int mcf() { int ans=0;FLOW=0; while (spfa()) ans+=GetAns(); return ans; } } int main() { using namespace MinCostFlow; scanf("%d",&n); tot=1; S=n+1;T=n+2; int ans=0; for (int i=1;i<=n;i++) { int x,y,d; scanf("%d",&x); degree[i]-=x; for (int j=1;j<=x;j++) { scanf("%d%d",&y,&d); add_edge(i,y,1<<29,d); degree[y]++;ans+=d; } if (i!=1) add_edge(i,1,1<<29,0); } for (int i=1;i<=n;i++) { if (degree[i]>0) add_edge(S,i,degree[i],0); if (degree[i]<0) add_edge(i,T,-degree[i],0); } printf("%d\n",mcf()+ans); return 0; } |