题面
分析
本质上是网络流加上了一个花费值。
我们在网络流的分层时使用了BFS,在BFS上加上最小花费(边权),就会想到用SPFA,可以处理负权的情况,十分优秀。
就是先用SPFA跑关于费用的最短路,一边用一个flow数组记录一条路上的最小容量限制,记录前驱结点。然后从汇点回溯到源点,每条边的容量减去流量并处理反向边,统计答案就是每次 f l o w [ t ] flow[t] flow[t]的和,费用计算就显然了。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int inf=1e9;
struct node
{
int to,next,w,c;
}e[100010];
int n,m,s,t;
int tot=1,hd[100010];
int dis[5010],flow[5010],v[5010],pre[100010];
int mxflow,mncost;
void add(int x,int y,int w,int c)
{
e[++tot]=(node){y,hd[x],w,c};
hd[x]=tot;
}
bool spfa()
{
queue<int> q;
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(v,0,sizeof(v));
dis[s]=0;
q.push(s);
v[s]=1;
flow[s]=inf;
while(!q.empty())
{
int x=q.front();
q.pop();
v[x]=0;
for(int i=hd[x];i;i=e[i].next)
{
int t=e[i].to;
if(dis[t]>dis[x]+e[i].c&&e[i].w)
{
dis[t]=dis[x]+e[i].c;
flow[t]=min(flow[x],e[i].w);
pre[t]=i;
if(!v[t])
{
v[t]=1;
q.push(t);
}
}
}
}
return dis[t]!=1061109567;
}
void find()
{
int x=t;
while(x!=s)
{
int i=pre[x];
e[i].w-=flow[t];
e[i^1].w+=flow[t];
x=e[i^1].to;
}
mxflow+=flow[t];
mncost+=flow[t]*dis[t];
}
int main()
{
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++)
{
int x,y,w,c;
scanf("%d%d%d%d",&x,&y,&w,&c);
add(x,y,w,c);
add(y,x,0,-c);
}
while(spfa())
{
find();
}
cout<<mxflow<<' '<<mncost;
return 0;
}