bzoj1834(网络流+费用流)

来源:互联网 发布:usb打印机怎样网络共享 编辑:程序博客网 时间:2024/06/05 18:47

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


第一问裸的网络流

第二问:新建一个汇点,将n号点与汇点相连,容量为k,(限制最多增大的流量)费用为0;

将原先每一条边都新建一个边,容量为inf,表示可以任意大的扩建,费用的该边扩展所需的费用,如果原先的那一条边没有满,那么费用流时肯定是走那条边

如果满了,就可能走扩展的边,同时cost一定的费用;

跑费用流

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<cmath>#include<iostream>#include<queue>#define debug(x) cout<<#x<<"="<<x<<endlusing namespace std;const int N=100009;const int inf=0x3f3f3f3f;struct aa{int cap,flow,pre,to,w,from;}edge[100009];int head[N],tot,cur[N],ww[N];int n,m,k,lev[N];int pre[N],dis[N],id[N],t;bool b[N];inline int read(){int ans;char ch;ch='\0';while (ch<'0'||ch>'9') ch=getchar();ans=ch-'0';while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';return ans;}void addedge(int x,int y,int z,int w){edge[++tot].to=y;edge[tot].pre=head[x];head[x]=tot;edge[tot].cap=z;edge[tot].w=w;edge[tot].from=x;}bool bfs(){memset(lev,0,sizeof(lev));queue<int> q;q.push(1);lev[1]=1;while(!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=edge[i].pre)if (!lev[edge[i].to]&&edge[i].cap>edge[i].flow) {lev[edge[i].to]=lev[u]+1;if (edge[i].to==n) return true;q.push(edge[i].to);}}return false;}int dfs(int u,int maxflow){if (u==n||maxflow==0) return maxflow;int ans=0,&i=cur[u];for (;i;i=edge[i].pre)if (lev[edge[i].to]==lev[u]+1){int flow=dfs(edge[i].to,min(edge[i].cap-edge[i].flow,maxflow));ans+=flow;maxflow-=flow;edge[i].flow+=flow;edge[((i-1)^1)+1].flow-=flow;if (maxflow==0) return ans;}return ans;}int work1(){int ans=0;while (bfs()) {for (int i=1;i<=n;i++) cur[i]=head[i];ans+=dfs(1,inf);}return ans;}bool spfa(){memset(pre,0,sizeof(pre));memset(b,false,sizeof(b));memset(dis,inf,sizeof(dis));memset(id,0,sizeof(id));pre[1]=-1;dis[1]=0;b[1]=true;queue<int> q;q.push(1);while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=edge[i].pre)if (dis[edge[i].to]>dis[u]+edge[i].w)if (edge[i].cap>edge[i].flow){dis[edge[i].to]=dis[u]+edge[i].w;pre[edge[i].to]=u;id[edge[i].to]=i;if (!b[edge[i].to]){b[edge[i].to]=true;q.push(edge[i].to);}}b[u]=false;}if (dis[t]==inf) return false;return true;}int work2(){int ans=0,h=tot;for (int i=1;i<=h;i++) if (edge[i].cap>0)addedge(edge[i].from,edge[i].to,inf,ww[i]);//原先的正向边cap为infelse addedge(edge[i].from,edge[i].to,0,ww[i]);//反向边的cap应该为0,这里错了一次t=n+1;addedge(n,t,k,0);//限制扩容量while (spfa()){int flow=inf;for (int i=t;i!=1;i=pre[i])flow=min(flow,edge[id[i]].cap-edge[id[i]].flow);ans+=dis[t]*flow;for (int i=t;i!=1;i=pre[i])edge[id[i]].flow+=flow,edge[((id[i]-1)^1)+1].flow-=flow;}return ans;}int main(){n=read();m=read();k=read();int x,z,y,w;while (m--){x=read();y=read();z=read();w=read();addedge(x,y,z,0);ww[tot]=w;addedge(y,x,0,0);ww[tot]=-w;}printf("%d ",work1());printf("%d",work2());return 0;}


0 0