[BZOJ1834][ZJOI2010]network 网络扩容(isap+费用流)

题目描述

传送门

题解

Q1 傻逼最大流
Q2 求出最大流之后将图暴力重构,原图中的边费用为0,流量为初始流量,添加一些和原图边同始同终的边,费用为扩容费用,流量为INF,再添加一个超级源连向原先的源点,费用为0,流量为k+maxflow来限流,求最小费用流即可。
思路如此简单我这个傻逼刚开始想错了,,,Orz ATP

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int max_n=1e3+5;
const int max_m=5e4+5;
const int max_e=max_m*2;
const int INF=1e9;

int n,m,k,cap,maxflow,mincost;
int tot,point[max_n],next[max_e],v[max_e],remain[max_e],c[max_e];
int deep[max_n],cur[max_n],last[max_n],num[max_n],dis[max_n];
bool vis[max_n];
struct hp{int x,y,cap,w;}edge[max_m];
queue <int> q;

inline void addedge(int x,int y,int cap,int z){
    ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap; c[tot]=z;
    ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; c[tot]=-z;
}

inline void bfs(int t){
    for (int i=1;i<=n;++i) deep[i]=n; deep[t]=0;
    while (!q.empty()) q.pop(); q.push(t);
    while (!q.empty()){
        int now=q.front(); q.pop();
        for (int i=point[now];i!=-1;i=next[i])
          if (deep[v[i]]==n&&remain[i^1]){
            deep[v[i]]=deep[now]+1;
            q.push(v[i]);
          }
    }
}
inline int addflow(int s,int t){
    int now=t,ans=INF;
    while (now!=s){
        ans=min(ans,remain[last[now]]);
        now=v[last[now]^1];
    }
    now=t;
    while (now!=s){
        remain[last[now]]-=ans;
        remain[last[now]^1]+=ans;
        now=v[last[now]^1];
    }
    return ans;
}
inline void isap(int s,int t){
    bfs(t);
    for (int i=1;i<=n;++i) ++num[deep[i]];
    for (int i=1;i<=n;++i) cur[i]=point[i];

    int now=s;
    while (deep[s]<n){
        if (now==t){
            maxflow+=addflow(s,t);
            now=s;
        }

        bool has_find=false;
        for (int i=cur[now];i!=-1;i=next[i])
          if (deep[v[i]]+1==deep[now]&&remain[i]){
            has_find=true;
            cur[now]=i;
            last[v[i]]=i;
            now=v[i];
            break;
          }

        if (!has_find){
            int minn=n-1;
            for (int i=point[now];i!=-1;i=next[i])
              if (remain[i]) minn=min(minn,deep[v[i]]);
            if (!(--num[deep[now]])) break;
            num[deep[now]=minn+1]++;
            cur[now]=point[now];
            if (now!=s) now=v[last[now]^1];
        }
    }
}
inline bool bfs(int s,int t){
    memset(dis,0x7f,sizeof(dis)); dis[n+1]=0;
    memset(vis,0,sizeof(vis)); vis[n+1]=true;
    while (!q.empty()) q.pop(); q.push(n+1);
    while (!q.empty()){
        int now=q.front(); q.pop();
        vis[now]=false;
        for (int i=point[now];i!=-1;i=next[i])
          if (dis[v[i]]>dis[now]+c[i]&&remain[i]){
            dis[v[i]]=dis[now]+c[i];
            last[v[i]]=i;
            if (!vis[v[i]]){
                vis[v[i]]=true;
                q.push(v[i]);
            }
          }
    }
    if (dis[t]>INF) return false;
    int flow=addflow(s,t);
    mincost+=dis[t]*flow;
    return true;
}
inline void min_cost_flow(int s,int t){
    mincost=0;
    while (bfs(s,t));
}
inline void rebuild(){
    tot=-1;
    memset(point,-1,sizeof(point));
    memset(next,-1,sizeof(next));
    for (int i=1;i<=m;++i){
        addedge(edge[i].x,edge[i].y,edge[i].cap,0);
        addedge(edge[i].x,edge[i].y,INF,edge[i].w);
    }
    addedge(n+1,1,maxflow+k,0);
    min_cost_flow(n+1,n);
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    tot=-1;
    memset(next,-1,sizeof(next));
    memset(point,-1,sizeof(point));
    for (int i=1;i<=m;++i){
        scanf("%d%d%d%d",&edge[i].x,&edge[i].y,&edge[i].cap,&edge[i].w);
        addedge(edge[i].x,edge[i].y,edge[i].cap,0);
    }
    isap(1,n);
    printf("%d ",maxflow);
    rebuild();
    printf("%d\n",mincost);
}

你可能感兴趣的:(网络流,ZJOI,bzoj)