其实就是最大流的层次图改成了最短路
以每条边的费用作为距离用SPFA求最短路
同时寻找源点到汇点的增广路
incf[u]表示从源点到u的可以增广的最大流量
每次求最短路到达汇点t的同时也就求出了incf[t]
然后再从汇点反向通过增广路构造新的残量网络
并同时更新当前最大流与最小费用
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int inf=1128481603;
const int maxn=10010;
int n,m,s,t;
struct node{int v,f,c,nxt;}E[200010];
int head[maxn],tot=1;
int dis[maxn],vis[maxn];
int incf[maxn],pre[maxn];
int maxf,fee;
void add(int u,int v,int f,int c)
{
E[++tot].nxt=head[u];
E[tot].v=v; E[tot].f=f; E[tot].c=c;
head[u]=tot;
}
int bfs()
{
queue<int> q; q.push(s); incf[s]=inf;
memset(dis,67,sizeof(dis)); dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop(); vis[u]=0;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(dis[v]>dis[u]+E[i].c&&E[i].f)
{
dis[v]=dis[u]+E[i].c;
incf[v]=min(incf[u],E[i].f); pre[v]=i;
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}
return dis[t]!=inf;
}
void dfs()
{
int u=t;
while(u!=s)
{
int i=pre[u];
E[i].f-=incf[t]; E[i^1].f+=incf[t];
u=E[i^1].v;
}
maxf+=incf[t]; fee+=incf[t]*dis[t];
}
int main()
{
n=read();m=read();s=read();t=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read(),f=read(),c=read();
add(u,v,f,c); add(v,u,0,-c);
}
while(bfs()) dfs();
printf("%d %d",maxf,fee);
return 0;
}