https://www.luogu.org/problem/P3381
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define inf 100010
using namespace std;
int point[2*inf],next1[2*inf],first[2*inf],cap[2*inf],cost[2*inf];
bool vis[inf];
int pre[inf],path[inf],dis[inf];
//pre[i] 表示 i号节点 的前驱节点
//path[i] 表示 i号节点 的前驱边
int n,m,s,t,min_cost,max_flow,k;
void edge(int,int,int,int);
int MinCostMaxFlow(int,int);
bool SPFA(int,int);
queue<int>q;
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
memset(first,0xff, sizeof(first));
for(int i = 1; i <= m; i++)
{
int u,v,w,f;
scanf("%d%d%d%d",&u,&v,&w,&f);
edge(u,v,w,f);//有向边建边一次
}
MinCostMaxFlow(s,t);
printf("%d %d",max_flow,min_cost);
}
bool SPFA(int s,int t)
{
memset(dis,0x7f, sizeof(dis));//10亿+
memset(pre,0xff, sizeof(pre));//-1
memset(vis, false, sizeof(vis));
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty())
{
int now = q.front();
q.pop();
vis[now] = false;
for(int k = first[now];k != -1;k = next1[k])
{
int new1 = point[k];
if(cap[k] > 0 && dis[now] + cost[k] < dis[new1])
{
dis[new1] = dis[now] + cost[k];
pre[new1] = now;
path[new1] = k;
if(!vis[new1]) vis[new1] = true,q.push(new1);
}
}
}
if(pre[t] == -1) return false;
return true;
}
int MinCostMaxFlow(int s,int t)
{
min_cost = 0,max_flow = 0;
while(SPFA(s,t))
{
int mi = 1e9;
for(int i = t;i != s;i = pre[i])
{
if(cap[path[i]] < mi)
mi = cap[path[i]];
}
max_flow += mi;
min_cost += dis[t]*mi;
for(int i = t;i != s;i = pre[i]){
cap[path[i]] -= mi;
cap[path[i]^1] += mi;//用异或快很多!!! 不要奇偶性!!!
}
}
}
void edge(int u,int v,int w,int f)//建边 从 0号 开始建边
{
point[k] = v;next1[k] = first[u];first[u] = k;
cap[k] = w;cost[k++] = f;
point[k] = u;next1[k] = first[v];first[v] = k;
cap[k] = 0;cost[k++] = -f;
}