bzoj1834: [ZJOI2010]network 网络扩容

这道题分为俩步,第一是求最大流,第二是在第一问的残量网络上求最小费用流。

建图时俩个点直接连2条边,一条容量为f[i],费用为0,另一条容量为inf,费用为c[i].这样就可以跑俩个算法了

第二问设一个虚拟源点S与1连容量为k,费用为0的边,n与一个虚拟汇点T连容量为k,费用为0的边。这样一直跑,最后只会增加k的流量。

记住bool一定要用true和false,用0和1tle了。。不知道为啥,但一定要记住

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 2000 + 10;
const int maxm = 40000 + 10;
const int INF = 0x3f3f3f3f;

int n,m,k,eid = -1,S,T,vnum,l,r;
int v[maxm],f[maxm],c[maxm],next[maxm];
int h[maxn],d[maxn],gap[maxn],q[maxn],pre[maxn];
bool inque[maxn];

void add(int a,int b,int F,int C) {
    v[++eid] = b; f[eid] = F; c[eid] = C; next[eid] = h[a]; h[a] = eid;
    v[++eid] = a; f[eid] = 0; c[eid] = -C; next[eid] = h[b]; h[b] = eid;
}

int ISAP(int u,int flow) {
    if(u == T) return flow;
    
    int cur = 0,aug,mindist = vnum;
    for(int i = h[u]; ~i; i = next[i]) 
        if(f[i] && !c[i] && d[v[i]] + 1 == d[u]) {
            aug = ISAP(v[i],min(f[i],flow-cur));
            f[i] -= aug;
            f[i^1] += aug;
            cur += aug;
            if(cur == flow || d[S] >= vnum) return cur;
        }
    if(!cur) {
        if(!--gap[d[u]]) {
            d[S] = vnum;
            return cur;
        }
        for(int i = h[u]; ~i; i = next[i]) if(f[i] && !c[i])
            mindist = min(mindist,d[v[i]]);
        ++gap[d[u]=mindist+1];
    }
    return cur;
}

int max_flow() {
    int res = 0;
    gap[0] = vnum = n;
    S = 1; T = n;
    while(d[S] < vnum) 
        res += ISAP(S,INF);
    return res;
}

void build() {
    scanf("%d%d%d",&n,&m,&k);
    memset(h,-1,sizeof(h));
    for(int i = 1,a,b,f,c; i <= m ; i++) {
        scanf("%d%d%d%d",&a,&b,&f,&c);
        add(a,b,f,0);
        add(a,b,INF,c);
    }
}

bool spfa() {
    for(int i = 1; i <= T; i++) d[i] = INF;
    l =0,r = 0;
    int u;
    d[S] = 0; inque[q[r++] = S] = true;
    while(l < r) {
        inque[u = q[l++]] = false;
        for(int i = h[u]; ~i ; i = next[i]) 
            if(f[i] && d[v[i]] > d[u] + c[i]) {
                d[v[i]] = d[u] + c[i];
                pre[v[i]] = i;
                if(!inque[v[i]]) inque[q[r++]=v[i]] = true;
            }
    }
    
    return (d[T] < INF);
}

int augment() {
    int aug = INF,res = 0;
    for(int i = T; i != S; i = v[pre[i]^1]) {
        aug = min(aug,f[pre[i]]);
    }
    
    for(int i = T; i != S; i = v[pre[i]^1]) {
        f[pre[i]] -= aug;
        f[pre[i]^1] += aug;
        res += c[pre[i]]*aug;
    }
    return res;
}

int cost_flow() {
    int res = 0;
    S = n+1; T = n+2;
    add(S,1,k,0);
    add(n,T,k,0);
    while(spfa()) 
        res += augment();
    return res;
}

void sovle() {
    printf("%d ",max_flow());
    printf("%d\n",cost_flow());
}

int main() {
    build();
    sovle();
    return 0;
}
posted @ 2016-04-11 21:07  invoid  阅读(189)  评论(0编辑  收藏  举报