码迷,mamicode.com
首页 > 其他好文 > 详细

P2604 [ZJOI2010]网络扩容

时间:2019-09-19 19:35:33      阅读:51      评论:0      收藏:0      [点我收藏+]

标签:最小   copy   head   ==   sam   scanf   bsp   pac   包含   

题目描述

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

输入格式

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

输出格式

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

输入输出样例

输入 #1
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
输出 #1
13 19

说明/提示

30%的数据中,N<=100

100%的数据中,N<=1000,M<=5000,K<=10

思路

有点暴力。先跑一遍dinic,求出第一问的解,再重新建图,讲扩容记为容量inf,费用的边,最后新建t点,容量为maxflow+k,跑最大流最小费用,即可得到ans。

代码

#include<bits/stdc++.h>
#define N 10700
#define M 107000
#define inf 1<<29
using namespace std;
struct node{
    int x,y,z,p,next;
}e[M*2];
int tot=1,head[N],maxflow=0,ans=0;
int x[M],y[M],z[M],cost[M];
int n,m,s,t,K;
void add(int x,int y,int z,int p){
    e[++tot].y=y;e[tot].z=z;e[tot].p=p;e[tot].next=head[x];head[x]=tot;
    e[++tot].y=x;e[tot].z=0;e[tot].p=-p;e[tot].next=head[y];head[y]=tot;
}
int incf[N],v[N],pre[N],d[N];
queue<int> q;
bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size()) q.pop();
    q.push(s);d[s]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y,z=e[i].z;
            if(z&&!d[y]){
                q.push(y);d[y]=d[x]+1;
                if(y==t) return 1;
            }
        } 
    }
    return 0;
}
int dinic(int x,int flow){
    if(x==t) return flow;
    int rest=flow,k;
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].y,z=e[i].z;
        if(z&&d[y]==d[x]+1){
            k=dinic(y,min(rest,z));
            if(!k) d[y]=0;
            e[i].z-=k;
            e[i^1].z+=k;
            rest-=k; 
        }
    }
    return flow-rest;
}
bool spfa(){
    queue<int> q;
    memset(d,0x3f,sizeof(d));// 0xcf
    memset(v,0,sizeof(v));
    q.push(s);d[s]=0;v[s]=1;
    incf[s]=inf;
    while(q.size()){
        int x=q.front();v[x]=0;q.pop();
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y,z=e[i].z;
            if(!z) continue;
            if(d[y]>d[x]+e[i].p){//d[y]<d[x]+e[i].p
                d[y]=d[x]+e[i].p;
                incf[y]=min(incf[x],z);
                pre[y]=i;
                if(!v[y]) v[y]=1,q.push(y);
            }
        }
    }
    if(d[t]==0x3f3f3f3f) return false;//0xcfcfcfcf
    return true;
}
void update(){
    int x=t;
    while(x!=s){
        int i=pre[x];
        e[i].z-=incf[t];
        e[i^1].z+=incf[t];
        x=e[i^1].y; 
    }
    maxflow+=incf[t];
    ans+=d[t]*incf[t];
}
void rebuild(){
    s=1;t=n+1;
    memset(head,0,sizeof(head));tot=1;
    for(int i=1;i<=m;i++){
        add(x[i],y[i],z[i],0);
        add(x[i],y[i],inf,cost[i]);
    }
    add(n,n+1,maxflow+K,0);
}
int main()
{
    int flow=0;
    cin>>n>>m>>K;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&x[i],&y[i],&z[i],&cost[i]);
        add(x[i],y[i],z[i],0);
    } s=1;t=n;
    while(bfs()) 
        while(flow=dinic(s,inf)) maxflow+=flow;
    cout<<maxflow<<" ";
    rebuild();
    while(spfa()) update();
    cout<<ans<<endl;
    return 0;
}

 

P2604 [ZJOI2010]网络扩容

标签:最小   copy   head   ==   sam   scanf   bsp   pac   包含   

原文地址:https://www.cnblogs.com/wangyiding2003/p/11551722.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!