给定一张有向图,每条边都有一个容量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<<endl
using 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为inf
else 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;
}