BZOJ传送门
洛谷传送门
解析:
残余网络的巧妙利用。。。
其实就是那种做过一次就会一类的题。。。
有谁想到这道题可以直接利用第一问跑完最大流的残量网络跑费用流呢。。
思路:
第一问是一个显然的最大流。
然而第二问很多人就被卡住了,扩容?还有费用?
我们先想一想,扩容怎么处理,我们再建立一个超级源,向111连一条容量为kkk的边,表示这一次需要扩容kkk的流量。
然后我们把原来的每条边再残量网络上建新边,容量为INFINFINF,费用就是扩容费用。
然后直接跑最小费用最大流。
为什么是对的?
首先第二次的最大流肯定是kkk。。。这很显然,不然第一次的最大流肯定就是0。因为无法到达。但是哪怕第一次最大流是0,扩容之后的原0边可能会带来流量的增大。
之后跑出来最大流kkk就是增加的流量,费用就是选择一些边扩容的最小费用。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=1003,M=10004,INF=0x3f3f3f3f;
int last[N],nxt[M<<1],to[M<<1],ecnt=1;
int from[M<<1],cap[M<<1],w[M<<1];
int S=1,T;
inline void addedge(int u,int v,int val,int val2){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,cap[ecnt]=val,w[ecnt]=val2,from[ecnt]=u;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,cap[ecnt]=0, w[ecnt]=-val2,from[ecnt]=v;
}
int lev[N],cur[N];
inline bool BFS(){
memset(lev,-1,sizeof lev);
queue<int> q;
q.push(S);lev[S]=0;cur[S]=last[S];
while(!q.empty()){
int u=q.front();
q.pop();
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&lev[v]==-1){
lev[v]=lev[u]+1;
if(v==T)return true;
q.push(v);
cur[v]=last[v];
}
}
}
return false;
}
inline int Dinic(cs int &u,cs int &flow){
if(u==T)return flow;
int ans=0;
for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&lev[v]>lev[u]){
int delta=Dinic(v,min(cap[e],flow-ans));
if(delta){
cap[e]-=delta;
cap[e^1]+=delta;
ans+=delta;
if(ans==flow)return flow;
}
}
}
lev[u]=-1;
return ans;
}
inline int maxflow(){
int ans=0;
while(BFS())ans+=Dinic(S,INF);
return ans;
}
inline void build(){
int t=ecnt;
for(int re i=2;i<=t;i+=2){
addedge(from[i],to[i],INF,w[i]);
w[i]=w[i^1]=0;
}
}
bool vis[N];
int dist[N];
inline bool SPFA(){
// cerr<<"enter SPFA"<<endl;
memset(vis,0,sizeof vis);
memset(dist,0x3f,sizeof dist);
queue<int> q;
q.push(S);
dist[S]=0;
cur[S]=last[S];;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&dist[v]>dist[u]+w[e]){
dist[v]=dist[u]+w[e];
if(!vis[v]){
cur[v]=last[v];
vis[v]=true;
q.push(v);
}
}
}
}
// cerr<<"finished SPFA"<<endl;
return dist[T]<INF;
}
inline int dfs(cs int &u,cs int &flow,int &co){
if(u==T){
co+=flow*dist[T];
return flow;
}
int ans=0;
vis[u]=true;
for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&dist[v]==dist[u]+w[e]&&!vis[v]){
int delta=dfs(v,min(flow-ans,cap[e]),co);
if(delta){
cap[e]-=delta;
cap[e^1]+=delta;
ans+=delta;
if(ans==flow)return flow;
}
}
}
return ans;
}
inline int MCMF(){
int co=0;
S=0;
while(SPFA())dfs(S,INF,co);
return co;
}
int n,m,k;
signed main(){
n=T=getint();
m=getint();
k=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint(),val=getint(),cost=getint();
addedge(u,v,val,cost);
}
cout<<maxflow()<<" ";
build();
addedge(S=0,1,k,0);
cout<<MCMF();
return 0;
}