题目大意:给定一张有向图,每条边都有一个容量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-100000
bool 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;
}