• BZOJ1834: [ZJOI2010]network 网络扩容


    BZOJ1834: [ZJOI2010]network 网络扩容

    Description

    给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。
    求: 
    1、在不扩容的情况下,1到N的最大流; 
    2、将1到N的最大流增加K所需的最小扩容费用。

    Input

    第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 
    接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
    N<=1000,M<=5000,K<=10

    Output

    输出文件一行包含两个整数,分别表示问题1和问题2的答案。

    Sample Input

    5 8 2
    1 2 5 8
    2 5 9 9
    5 1 6 2
    5 1 1 8
    1 2 8 7
    2 5 4 9
    1 2 1 1
    1 4 2 1

    Sample Output

    13 19
     
    题解Here!
    第1问显然最大流,Dinic 或者 ISAP 都可以。
    关键第2问。
    最小费用,当然 EK 。
    但是怎么建图呢?
    一开始想法是重新建图,流量均为 MAX ,费用不变,再从 0 连一条流量为 k 费用为 0 的边到 1 。
    但是这种算法是错的。。。
    因为最终的流量==先前的最大流+k。
    所以我们可以在原来的残余网络上再建一次原图,流量均为 MAX ,费用不变,再从 0 连一条流量为 k 费用为 0 的边到 1 ,即可。
    Dinic+EK真的好。。。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 5010
    #define MAX 999999999
    using namespace std;
    int n,m,k,s,t,c=2,mincost=0;
    int head[MAXN],deep[MAXN],fa[MAXN],flow[MAXN],path[MAXN];
    bool vis[MAXN];
    struct node{
    	int next,to,w,cost;
    }a[MAXN<<2];
    struct edge{
        int u,v,w,cost;
    }b[MAXN];
    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 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 bfs(){
    	int u,v;
    	queue<int> q;
    	for(int i=1;i<=n;i++)deep[i]=0;
    	deep[s]=1;
    	q.push(s);
    	while(!q.empty()){
    		u=q.front();
    		q.pop();
    		for(int i=head[u];i;i=a[i].next){
    			v=a[i].to;
    			if(a[i].w&&!deep[v]){
    				deep[v]=deep[u]+1;
    				if(v==t)return true;
    				q.push(v);
    			}
    		}
    	}
    	return false;
    }
    int dfs(int x,int limit){
    	if(x==t)return limit;
    	int v,sum,cost=0;
    	for(int i=head[x];i;i=a[i].next){
    		v=a[i].to;
    		if(a[i].w&&deep[v]==deep[x]+1){
    			sum=dfs(v,min(a[i].w,limit-cost));
    			if(sum>0){
    				a[i].w-=sum;
    				a[i^1].w+=sum;
    				cost+=sum;
    				if(limit==cost)break;
    			}
    			else deep[v]=-1;
    		}
    	}
    	return cost;
    }
    int dinic(){
    	int ans=0;
    	while(bfs())ans+=dfs(s,MAX);
    	return ans;
    }
    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;
    }
    bool spfa(){
        int u,v;
        queue<int> q;
        for(int i=1;i<=n+1;i++){path[i]=MAX;vis[i]=false;fa[i]=-1;deep[i]=0;}
        path[s]=0;
        vis[s]=true;
        fa[s]=0;
        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];
            }
            mincost+=flow[t]*path[t];
        }
    }
    void work(){
        printf("%d ",dinic());
        for(int i=1;i<=m;i++)add(b[i].u,b[i].v,MAX,b[i].cost);
        s=n+1;
        add(s,1,k,0);
        EK();
        printf("%d
    ",mincost);
    }
    void init(){
    	n=read();m=read();k=read();
    	s=1;t=n;
    	for(int i=1;i<=m;i++){
    		b[i].u=read();b[i].v=read();b[i].w=read();b[i].cost=read();
    		add(b[i].u,b[i].v,b[i].w,0);
    	}
    }
    int main(){
    	init();
    	work();
    	return 0;
    }
    
  • 相关阅读:
    ZeroMQ接口函数之 :zmq_z85_decode – 从一个用Z85算法生成的文本中解析出二进制密码
    ZeroMQ接口函数之 :zmq_init
    ZeroMQ接口函数之 :zmq_errno – 返回errno的值给调用此函数的线程
    ZeroMQ接口函数之 :zmq_disconnect
    ZeroMQ接口函数之 :zmq_curve_keypair
    ZeroMQ接口函数之 :zmq_curve – 安全的认证方式和保密方式
    ZeroMQ接口函数之 :zmq_ctx_term
    ZeroMQ接口函数之 :zmq_socket_monitor
    ZeroMQ接口函数之 :zmq_ctx_shutdown
    ZeroMQ接口函数之 :zmq_ctx_set
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/8977414.html
Copyright © 2020-2023  润新知