1834: [ZJOI2010]network 网络扩容

来源:互联网 发布:xampp mysql mac设置 编辑:程序博客网 时间:2024/05/21 07:15

题目链接

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

题解:
第一问直接上模板
对于第二问,我们可以设图中原有的边费用为0,在残量网络上继续增广。显然残量网络中有流量的边都是有可以直接流的,并且不需要任何费用。
然后我们对于原图中的每一条边,新建一条容量为INF,费用为扩容费用的边。
新建源s,连(s,1,k,0),控制流量。
跑一遍最小费用最大流即可。

我的收获:打板子好累啊……

#include <iostream>#include <cstdio>#include <cstring>#include <climits>#include <algorithm>using namespace std;const int M=100005;const int MM=200005;#define INF INT_MAX-100000bool Exit;int n,m,k,t,st,ed,ret;int head[M],dis[M],vis[M],last[M],pre[M];int d[M],num[M],vi[MM],q[MM],us[MM],uv[MM];struct edge{int fro,to,val,c,nex;}e[MM];//先费用后流量…… void add(int u,int v,int w,int c){e[t]=(edge){u,v,w,c,head[u]};last[u]=head[u]=t++;}void insert(int u,int v,int w,int c){add(u,v,w,c),add(v,u,-w,0);}namespace FLOW{bool spfa(){    for(int i=0;i<=ed;i++) vis[i]=0,dis[i]=INF;    int h=0,w=0;dis[st]=0;q[++w]=st;    while(h<w){        int u=q[++h];vis[u]=1;        for(int i=head[u];i!=-1;i=e[i].nex){            int v=e[i].to;            if(e[i].c&&dis[v]>dis[u]+e[i].val){                dis[v]=dis[u]+e[i].val;                pre[v]=i;                if(!vis[v]) vis[v]=1,q[++w]=v;            }        }    }    return dis[ed]!=INF;}void flow(){    int mx=INF;    for(int u=ed;u!=st;u=e[pre[u]].fro)        mx=min(mx,e[pre[u]].c);    for(int u=ed;u!=st;u=e[pre[u]].fro){        e[pre[u]].c-=mx,e[pre[u]^1].c+=mx;        ret+=mx*e[pre[u]].val;    }}int dfs(int x,int in){    if(x==ed) return in;    int ans=0,f;    for(int i=last[x];i!=-1;last[x]=i=e[i].nex){        int v=e[i].to;        if(e[i].c&&d[v]==d[x]-1){            f=dfs(v,min(in-ans,e[i].c));            ans+=f;            e[i].c-=f,e[i^1].c+=f;            if(Exit||ans==in) return ans;        }    }    if(--num[d[x]]==0) Exit=1;    d[x]++,num[d[x]]++,last[x]=head[x];    return ans;}int mflow(){    int ansx=0;    while(!Exit) ansx+=dfs(st,INF);    return ansx;}void cflow(){    while(spfa()) flow();}}void rebuild(){    st=0;insert(st,1,0,k);    for(int i=1;i<=m;i++) insert(us[i],uv[i],vi[i],INF);}void work(){    cout<<FLOW::mflow()<<" ";    rebuild();    FLOW::cflow();    cout<<ret<<endl;}void init(){    int x,y,z;    t=0;memset(head,-1,sizeof(head));    cin>>n>>m>>k;    for(int i=1;i<=m;i++)        scanf("%d%d%d%d",&us[i],&uv[i],&z,&vi[i]),insert(us[i],uv[i],0,z);    st=1,ed=n,num[0]=n;}int main(){    init();    work();    return 0;}
原创粉丝点击