zoukankan      html  css  js  c++  java
  • [AHOI2014]支线剧情(有上下界的网络流)

    [AHOI2014]支线剧情(有上下界的网络流)

    题面

    JYY现在所玩的RPG游戏中,一共有N个剧情点,由1到N编号,第i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点。当然如果为0,则说明i号剧情点是游戏的一个结局了。

    JYY观看一个支线剧情需要一定的时间。JYY一开始处在1号剧情点,也就是游戏的开始。显然任何一个剧情点都是从1号剧情点可达的。此外,随着游戏的进行,剧情是不可逆的。所以游戏保证从任意剧情点出发,都不能再回到这个剧情点。由于JYY过度使用修改器,导致游戏的“存档”和“读档”功能损坏了,

    所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到1号剧情点。JYY可以在任何时刻退出游戏并重新开始。不断开始新的游戏重复观看已经看过的剧情是很痛苦,JYY希望花费最少的时间,看完所有不同的支线剧情。
    (N leq 300)

    分析

    看完所有剧情,就是要求每条边至少经过一次。又因为时间可以叠加计算,容易想到有上下界的费用流。源点连向1号节点,出度为0的点连向汇点,流量上下界为([0,infin)).原图上的边上下界为([1,infin))即可。

    有上下界的网络流见网络流常见建图套路总结

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define maxn 100000 
    #define maxm 500000 
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    namespace MCMF{
        struct edge{
            int from;
            int to;
            int next;
            ll flow;
            ll cost; 
        }E[maxm*2+5];
        int head[maxn+5];
        int esz=1;
        void add_edge(int u,int v,ll w,ll c){
    //		printf("%d->%d vol=%lld cost=%lld
    ",u,v,w,c); 
            esz++;
            E[esz].from=u;
            E[esz].to=v;
            E[esz].flow=w;
            E[esz].cost=c;
            E[esz].next=head[u];
            head[u]=esz;
            esz++;
            E[esz].from=v;
            E[esz].to=u;
            E[esz].flow=0;
            E[esz].cost=-c;
            E[esz].next=head[v];
            head[v]=esz;
        }
        
        ll dist[maxn+5],minf[maxn+5],last[maxn+5];
        bool inq[maxn+5];
        bool spfa(int s,int t){
            queue<int>q;
            memset(minf,0x3f,sizeof(minf)); 
            memset(dist,0x3f,sizeof(dist));
            memset(inq,0,sizeof(q));
            q.push(s);
            dist[s]=0;
            inq[s]=1;
            while(!q.empty()){
                int x=q.front();
                q.pop();
                inq[x]=0;
                for(int i=head[x];i;i=E[i].next){
                    int y=E[i].to;
                    if(E[i].flow){
                        if(dist[y]>dist[x]+E[i].cost){
                            dist[y]=dist[x]+E[i].cost;
                            minf[y]=min(minf[x],E[i].flow);
                            last[y]=i;
                            if(!inq[y]){
                                inq[y]=1;
                                q.push(y);
                            }
                        }
                    }
                }
            }
            if(dist[t]==INF) return 0;
            else return 1;
        }
        
        void update(int s,int t){
            int x=t;
            while(x!=s){
                int i=last[x];
                E[i].flow-=minf[t];
                E[i^1].flow+=minf[t];
                x=E[i].from;
            }
        }
        ll mcmf(int s,int t){
            ll ct=0;
            while(spfa(s,t)){
                update(s,t);
                ct+=dist[t]*minf[t];
            }
            return ct;
        }
    } 
    namespace EXMCMF{
        struct _edge{
            int from;
            int to;
            ll lflow;
            ll rflow;
            ll cost; 
        }E[maxm+5];	
        int cnte=0,cntv=0;
        void adde(int u,int v,ll l,ll r,ll c){
            cnte++;
            cntv=max(max(u,v),cntv);
            E[cnte].from=u;
            E[cnte].to=v;
            E[cnte].lflow=l;
            E[cnte].rflow=r;
            E[cnte].cost=c;
        }
        ll dflow[maxn+5];
        ll solve(int s,int t){
            ll ans=0;
            int ss=cntv+1,tt=cntv+2;
            adde(t,s,0,INF,0);
            for(int i=1;i<=cnte;i++){
                dflow[E[i].from]-=E[i].lflow;
                dflow[E[i].to]+=E[i].lflow;
                ans+=E[i].lflow*E[i].cost;
                MCMF::add_edge(E[i].from,E[i].to,E[i].rflow-E[i].lflow,E[i].cost); 
            }
            for(int i=0;i<=cntv;i++){
                if(dflow[i]>0) MCMF::add_edge(ss,i,dflow[i],0);
                else if(dflow[i]<0) MCMF::add_edge(i,tt,-dflow[i],0);
            }
            return ans+MCMF::mcmf(ss,tt);
        }
    }
    
    int n;
    int main(){
        int k,w,v;
        scanf("%d",&n);
        int s=0,t=n+1;
        EXMCMF::adde(s,1,0,INF,0);
        for(int i=1;i<=n;i++){
            scanf("%d",&k);
            for(int j=1;j<=k;j++){
                scanf("%d %d",&v,&w);
                EXMCMF::adde(i,v,1,INF,w);
            }
            EXMCMF::adde(i,t,0,INF,0);
        }
        printf("%lld
    ",EXMCMF::solve(s,t)); 
    } 
    
  • 相关阅读:
    个人作业-数组3
    Java编程思想
    19年春第三周学习
    个人作业-数组2
    自我介绍
    个人作业-数组
    19春第二周学习心得
    fiddler--华为手机下载安装fiddler证书
    RF接口测试----post请求
    RF接口测试----get请求
  • 原文地址:https://www.cnblogs.com/birchtree/p/13404127.html
Copyright © 2011-2022 走看看