[bzoj1834][ZJOI2010] 网络扩容 最大流 费用流

[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的边。
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

30%的数据中,N<=100

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

我不知道为什么原始对偶挂了,进了死循环
所以学了普通费用流

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int inf = 0x7fffffff;
const int N = 1005;
const int M = 500000 + 5;
int n,m,k,ans=0,T,S;
int h[N],last[N],q[N],cnt=1,d[N],from[N];
bool inq[N];
template <class T>
inline bool readIn(T &x)  {
    T flag = 1;  char ch;
    while(!(isdigit(ch = (char) getchar())) && ch != EOF)  if( ch == '-' )  flag = -1;
    if(ch == EOF)  return false;
    for(x = ch - 48; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48);
    x *= flag;
    return true;
}
struct Edge{
    int to,v,c,next,from,c1;
}e[M];
void insert( int u, int v, int w, int c ){
    e[++cnt].next = last[u]; last[u] = cnt; e[cnt].c1 = c; e[cnt].to = v; e[cnt].v = w, e[cnt].from = u;
    e[++cnt].next = last[v]; last[v] = cnt; e[cnt].c1 = -c; e[cnt].to = u; e[cnt].v = 0, e[cnt].from = v;
}
void insert2( int u, int v, int w, int c ){
    e[++cnt].next = last[u]; last[u] = cnt; e[cnt].c = c; e[cnt].to = v; e[cnt].v = w, e[cnt].from = u;
    e[++cnt].next = last[v]; last[v] = cnt; e[cnt].c = -c; e[cnt].to = u; e[cnt].v = 0, e[cnt].from = v;
}
void rebuild(){
    int yu = cnt;
    for( int i = 2; i <= yu; i+=2 ) insert2(e[i].from,e[i].to,inf,e[i].c1);
    insert(0,1,k,0); ans = 0;
}
bool bfs(){
    int head = 0, tail = 1;
    memset(h,-1,sizeof(h));
    q[0] = 1; h[1] = 0;
    while( head != tail ){
        int now = q[head++]; if( head == n ) head = 0;
        for( int i = last[now]; i; i = e[i].next ){
            if( e[i].v && h[e[i].to] == -1 ){
                h[e[i].to] = h[now]+1;
                q[tail++] = e[i].to; if( tail == n ) tail = 0;
            }
        }
    }
    return h[n] != -1;
}
int dfs( int x, int f ){
    if( x == n ) return f;
    int w,used = 0;
    for( int i = last[x]; i; i = e[i].next )
        if( e[i].v && h[e[i].to] == h[x]+1 ){
            w = dfs( e[i].to, min(f-used,e[i].v) );
            e[i].v -= w; e[i^1].v += w; used += w;
            if( used == f ) return f;
        }
    if( !used ) h[x] = -1;
    return used;
}
void dinic(){
    while(bfs()){
        ans += dfs(1,inf);
    }
}
bool spfa(){
    for( int i = 1; i <= T; i++ ) d[i] = inf;
    int head = 0, tail = 1;
    q[0] = S; d[S] = 0; inq[S] = 1;
    while( head != tail ){
        int now = q[head++]; if( head == T ) head = 0;
        for( int i = last[now]; i; i = e[i].next)
            if( e[i].v && e[i].c + d[now] < d[e[i].to] ){
                d[e[i].to] = e[i].c + d[now];
                from[e[i].to] = i;
                if( !inq[e[i].to] ){
                    inq[e[i].to] = 1;
                    if( d[e[i].to] < d[q[head]] ){
                        head--; if( head == -1 ) head = T-1;
                        q[head] = e[i].to;
                    } else{
                        q[tail++] = e[i].to; if( tail == T ) tail = 0;
                    }
                }
            }
            inq[now] = 0;
    }
    return d[T] != inf;
}
void mcf(){
    int x = inf;
    for( int i = from[T]; i; i = from[e[i].from] ) x = min(x,e[i].v);
    for( int i = from[T]; i; i = from[e[i].from] ){
        ans += e[i].c*x;
        e[i].v -= x; e[i^1].v += x;
    }
}
int main(){
    readIn(n); readIn(m); readIn(k); T = n; S = 0;
    for( int i = 1; i <= m; i++ ){
        int u, v, w, c;
        readIn(u); readIn(v); readIn(w); readIn(c);
        insert(u,v,w,c);
    } dinic();
    printf("%d ", ans);
    rebuild();
    while(spfa())mcf(); printf("%d", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值