#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int maxn=1005;
int n,m;
struct ArcType{//弧结构
int c,f;//容量、流量
};
ArcType edge[maxn][maxn];//邻接矩阵、每个元素为ArcType类型
int flag[maxn];//顶点状态:-1--未标号、0-已标号未检查、1-已标号已检查
int pre[maxn];//标号的第一个分量、指明标号从哪个顶点得到,以便找出可改进量
int alpha[maxn];//标号的第二个分量:可改进两
int que[maxn];
int v;
int qs,qe;//队列头位置、尾位置
void ford() {
while(1){//标号直至不存在可改进路
memset(flag,-1,sizeof flag) ;
memset(pre,-1,sizeof pre);
memset(alpha,-1,sizeof alpha);
flag[0]=0,pre[0]=0,alpha[0]=INF;
qs=qe=0;
que[qe]=0;
qe++;
//qs<qe表示队列非空、flag[n-1]==-1表示汇点未标号
while(qs<qe&&flag[n-1]==-1) {
v=que[qs];
qs++;//取出队列头结点
for(int i=0;i<n;i++){//检查顶点v的正向和反向邻接顶点
if(flag[i]==-1){
if(edge[v][i].c<INF&&edge[v][i].f<edge[v][i].c){
flag[i]=0;
pre[i]=v;//给顶点i标号、(已标号未检查)
alpha[i]=min(alpha[v],edge[v][i].c-edge[v][i].f);
que[qe++] =i;//顶点i入队列
}
else if(edge[i][v].c<INF&&edge[i][v].f>0) {//反向且有流量
flag[i]=0;
pre[i]=-v;//给顶点i标号、(已标号未检查)
alpha[i]=min(alpha[v],edge[i][v].f);
que[qe++]=i;
}
}
}
flag[v]=1;
}
//当汇点没有获得标号或者汇点的调整量为0,应该退出while循环
if(flag[n-1]==-1||alpha[n-1]==0) break;
//当汇点有标号时、进行调整
int k1=n-1,k2=abs(pre[k1]);
int a=alpha[n-1];
while(1){
if(edge[k2][k1].f<INF){
edge[k2][k1].f+=a;
}else{
edge[k1][k2 ].f-=a;//反向
}
if(k2==0) break;//调整一直到源点v0
k1=k2;
k2=abs(pre[k1]) ;
}
}
int maxflow=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==0&&edge[i][j].f<INF)
maxflow+=edge[i][j].f;//源点的流出量、即最大流
}
}
printf("%d\n",maxflow);
}
int main(){
int u,v,c,f;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
edge[i][j].c=edge[i][j].f=INF;
}
}
for(int i=0;i<m;i++){
scanf("%d%d%d%d",&u,&v,&c,&f);
edge[u][v].c=c;
edge[u][v].f=f;
}
ford();
return 0;
}
/*
6 10
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2
*/
Ford-Fulkerson【一般增广 路算法】
猜你喜欢
转载自blog.csdn.net/qq_37867156/article/details/81390070
今日推荐
周排行