zoukankan      html  css  js  c++  java
  • BZOJ3876: [Ahoi2014&Jsoi2014]支线剧情

    BZOJ3876: [Ahoi2014&Jsoi2014]支线剧情

    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

     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

    题解Here!
    首先应该能发现这是个费用流的题。。。
    因为要把整个图走一遍,还有时间,于是费用流没得跑。

    走一次路径会给这条路径上的所有边增加$1$的流量,再给所有边赋一个费用等于边权。

    这样,我们只要设每条边的流量有一个$1$的下限,上限为无限大,就能做了。

    还要把所有的剧情结束点(没有出边的)连到一个超级汇点,源点就是$1$号点。

    跑一个最小费用可行流即可。

    什么?你不知道最小费用可行流?

    教程

    考虑一张网络流图,每条边定义为$(u,v,l,r,cost)$,代表从$u$到$v$的一条有向边,流量为$[l,r]$闭区间,费用为$cost$,源点$s$汇点$t$已知,且保证源点没有入边、汇点没有出边。

    同时定义常规费用流图的边为$(u,v,w,cost)$

    现在我们需要求这张图的最小费用可行流,就是满足所有边的流量上下限制,同时费用最小。

    按照如下方式建立附加边和附加点:

    1. 建立附加源点$S$,和附加汇点$T$
    2. 对于原图中每一个点,包括源汇点$s,t$,u,令$degree[u]$代表$u$点的所有入边的流量下界减去出边的流量下界。

    然后有两种情况:

    • 如果$degree[u]<0$,那么从$u$连一条边到$T$,即$(u,T,-degree[u],0)$
    • 如果$degree[u]>0$,那么从$S$连一条边到$u$,即$(S,u,degree[u],0)$

    3. 对于原图中每一条边$(u,v,l,r,cost)$,连边$(u,v,r-l,cost)$。

    4. 连边$(t,s,MAX,0)$。注意这里是原图的源汇点!不是附加的源汇点!

    这样以后,从$S$到$T$跑新图的最小费用最大流,再加上原图中每条边的下界流量乘以费用(必须跑的部分),就是最小费用可行流的费用了。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 310
    #define MAXM 5010
    #define MAX 999999999
    using namespace std;
    int n,m,s,t,S,T,c=2,maxflow=0,mincost=0,sum=0;
    int head[MAXN],deep[MAXN],flow[MAXN],path[MAXN],fa[MAXN],degree[MAXN];
    bool vis[MAXN];
    struct Edge{
        int next,to,w,cost;
    }a[MAXM<<2];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline int relax(int u,int v,int i,int w,int cost){
        if(path[v]>path[u]+cost){
            path[v]=path[u]+cost;
            fa[v]=u;
            deep[v]=i;
            flow[v]=min(flow[u],w);
            return 1;
        }
        return 0;
    }
    inline void add(int u,int v,int w,int cost){
        a[c].to=v;a[c].w=w;a[c].cost=cost;a[c].next=head[u];head[u]=c++;
        a[c].to=u;a[c].w=0;a[c].cost=-cost;a[c].next=head[v];head[v]=c++;
    }
    bool spfa(){
        int u,v;
        queue<int> q;
        for(int i=S;i<=T;i++){path[i]=MAX;vis[i]=false;deep[i]=0;fa[i]=-1;}
        path[S]=0;
        vis[S]=true;
        flow[S]=MAX;
        q.push(S);
        while(!q.empty()){
            u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=head[u];i;i=a[i].next){
                v=a[i].to;
                if(a[i].w&&relax(u,v,i,a[i].w,a[i].cost)&&!vis[v]){
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
        if(path[T]==MAX)return false;
        return true;
    }
    void EK(){
        while(spfa()){
            for(int i=T;i!=S;i=fa[i]){
                a[deep[i]].w-=flow[T];
                a[deep[i]^1].w+=flow[T];
            }
            maxflow+=flow[T];
            mincost+=flow[T]*path[T];
        }
    }
    void work(){
        EK();
        printf("%d
    ",sum+mincost);
    }
    void init(){
        int x,y,k;
        n=read();
        s=1;t=n+1;S=0;T=n+2;
        for(int i=1;i<=n;i++){
            k=read();
            degree[i]-=k;
            add(i,t,MAX,0);
            for(int j=1;j<=k;j++){
                x=read();y=read();
                degree[x]++;
                sum+=y;
                add(i,x,MAX,y);
            }
        }
        for(int i=1;i<=n;i++){
            if(degree[i]<0)add(i,T,-degree[i],0);
            if(degree[i]>0)add(S,i,degree[i],0);
        }
        add(t,s,MAX,0);
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    LeetCode Find Duplicate File in System
    LeetCode 681. Next Closest Time
    LeetCode 678. Valid Parenthesis String
    LeetCode 616. Add Bold Tag in String
    LeetCode 639. Decode Ways II
    LeetCode 536. Construct Binary Tree from String
    LeetCode 539. Minimum Time Difference
    LeetCode 635. Design Log Storage System
    LeetCode Split Concatenated Strings
    LeetCode 696. Count Binary Substrings
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9494847.html
Copyright © 2011-2022 走看看