最大流
int n, m; // 顶点和边数
int flow[100][100], cap[100][100]; // 流量和容量
int p[100]; // 上一个节点
int a[100]; // 从s到此节点最小残量
void read(){
cin >> n >> m;
for(int i = 0; i < m; i++){
int x, y, z;
cin >> x >> y >> z;
cap[x][y] = z;
}
}
int max_flow(int s, int t){
memset(flow, 0, sizeof(flow));
int f = 0;
while(true){
memset(a, 0, sizeof(a));
a[s] = INF;
queue<int> q;
q.push(s);
while(!q.empty()){ // BFS,找增广路
int u = q.front();
q.pop();
for(int i = 0; i < n; i++){
if(!a[i] && cap[u][i] > flow[u][i]){ // 找到满足的顶点
p[i] = u;
q.push(i);
if(cap[u][i] - flow[u][i] < a[u]){
a[i] = cap[u][i] - flow[u][i];
}else{
a[i] = a[u];
}
}
}
}
if(a[t] == 0) // 找不到,已是最大流
break;
for(int u = t; u != s; u = p[u]){ // 从t往回走
flow[p[u]][u] += a[t];
flow[u][p[u]] -= a[t];
}
f += a[t]; // 更新从s流出的流量
}
return f;
}
最小花费最大流
int n, m; // 顶点和边数
int flow[100][100], cap[100][100], cost[100][100]; // 流量、容量、单位花费
int p[100]; // 上一个节点
void read(){
cin >> n >> m;
for(int i = 0; i < m; i++){
int x, y, z, c;
cin >> x >> y >> z >> c;
cap[x][y] = z;
cost[x][y] = c;
}
}
pair<int, int> min_cost_max_flow(int s, int t){
memset(flow, 0, sizeof(flow));
int c = 0, f = 0;
while(true){
int d[100]; // s到节点的最短路
for(int i = 0; i < n; i++)
d[i] = INF;
d[s] = 0;
bool inq[100]; // 节点是否在队列
memset(inq, 0, sizeof(inq));
queue<int> q;
q.push(s);
while(!q.empty()){ // 因cost可能有负,用bellman-ford算法
int u = q.front();
q.pop();
inq[u] = false;
for(int v = 0; v < n; v++){
if(cap[u][v] > flow[u][v] && d[u] + cost[u][v] < d[v]){
d[v] = d[u] + cost[u][v];
p[v] = u;
if(!inq[v]){
q.push(v);
inq[v] = true;
}
}
}
}
if(d[t] == INF) // 已经是最小花费最大流
break;
int a = INF;
for(int u = t; u != s; u = p[u]){ // 求出s到t最小的残量
if(cap[p[u]][u] - flow[p[u]][u] < a){
a = cap[p[u]][u] - flow[p[u]][u];
}
}
for(int u = t; u != s; u = p[u]){ // 增广
flow[p[u]][u] += a;
flow[u][p[u]] -= a;
}
f += a;
c += a * d[t];
}
return make_pair(f, c);
}