zoukankan      html  css  js  c++  java
  • 【bzoj3876】支线剧情

    要求在dag里每条边上界INF下界1费用t。

    裸上下界费用流,好像没有什么特定的写法。

    首先每条边肯定至少走一次,不妨直接把每条边下界的费用先算上。原来的边正常连容量INF费用t,每个点向1连边表示可以随时返回。由于先计算了下界的费用而忽略下界,所以会导致流量不守恒,考虑普通上下界网络流的写法,新建原点s汇点t,统计每个点下界时流出的流量和流入的流量,此题即出度和入度,令d=入度-出度,若d>0则S向这个点连容量为d费用为0的边,若d<0则向T连容量为-d费用为0的边,跑一遍mcmf加上原来的费用就好了。

    #include<bits/stdc++.h>
    #define maxn 405
    #define maxm 100005
    #define INF 0x7f7f7f7f
    
    using namespace std;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    struct scsc{
        int next,from,to,w,c;
    }edge[maxm<<1];
    
    int Len,head[maxn],ind[maxn],otd[maxn],Sum;
    
    void addedge(int u,int v,int w,int c){
        edge[++Len].to=v;edge[Len].from=u;edge[Len].w=w;edge[Len].c=c;edge[Len].next=head[u];head[u]=Len;
        edge[++Len].to=u;edge[Len].from=v;edge[Len].w=0;edge[Len].c=-c;edge[Len].next=head[v];head[v]=Len;
    }
    
    int vis[maxn],d[maxn];
    
    int spfa(int s,int t){
        queue<int>Q;
        for(int i=s;i<=t;++i)vis[i]=0;
        for(int i=s;i<=t;++i)d[i]=INF;
        Q.push(s);vis[s]=1;d[s]=0;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int i=head[u];i;i=edge[i].next){
                int v=edge[i].to;
                if(edge[i].w&&d[v]>d[u]+edge[i].c){
                    d[v]=d[u]+edge[i].c;
                    if(!vis[v]){
                        vis[v]=1;
                        Q.push(v);
                    }
                }
            }
            vis[u]=0;
        }
        return d[t]!=INF;
    }
    
    int ans=0;
    
    int dfs(int u,int f,int t){
        vis[u]=1;
        if(u==t)return f;
        int used=0,w;
        for(int i=head[u];i&&used<f;i=edge[i].next){
            int v=edge[i].to;
            if(edge[i].w&&d[v]==d[u]+edge[i].c&&!vis[v]){
                w=dfs(v,min(f-used,edge[i].w),t);
                edge[i].w-=w;
                edge[i^1].w+=w;
                used+=w;
                ans+=edge[i].c*w;
            }
        }
        return used;
    }
    
    void mcmf(int s,int t){
        while(spfa(s,t)){
            vis[t]=1;
            while(vis[t]){
                for(int i=s;i<=t;++i)vis[i]=0;
                dfs(s,INF,t);
            }
        }
    }
    
    int n;
    
    int main(){
        n=read();int f1,f2;
        int S=0,T=n+1;Len=1;
        for(int i=1;i<=n;++i){
            otd[i]=read();
            for(int j=1;j<=otd[i];++j){
                f1=read();f2=read();
                ++ind[f1];Sum+=f2;
                addedge(i,f1,INF,f2);
            }
        }
        for(int i=2;i<=n;++i)addedge(i,1,INF,0);
        for(int i=2;i<=n;++i){
            int du=ind[i]-otd[i];
            if(du>0)addedge(S,i,du,0);
            else addedge(i,T,-du,0);
        }
        mcmf(S,T);
        printf("%d
    ",ans+Sum);
        return 0;
    }
  • 相关阅读:
    31.迭代器丶生成器
    30.面向对象中常用内建函数与重载函数丶自定义手动报错
    安装补全命令的包
    安装yum
    centos7时间同步
    yum解决 "Couldn't resolve host 'apt.sw.be'" 错误
    centos6多实例安装mysql
    openstack--部暑
    kvm安装
    如何将本地大文件通过终端上传到linux服务器
  • 原文地址:https://www.cnblogs.com/illya/p/7567471.html
Copyright © 2011-2022 走看看