最大流与最小割是图论里最经典的算法之一:为了实现这个算法,储存方面我用的是图的邻接表而不是邻接矩阵,因为我觉得邻接表效率会更快一点,而算法方面我用的是广度优先搜索,这种方法效率也是比较高的,下面就是我的算法的c++实现:
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
#include<stdio.h>
#define MAX 999999
using namespace std;
class Graph
{
private:
struct vertex
{
int num ; //编号
int flag ; //正向或负向标记
int ver ; //来自哪条边
int flow; //流量标记
vector<int>f_edge ; //前向边
vector<int>u ; //前向边的流量
vector<int>b_edge; //后向边
vector<int>x ; //后向边的流量
vertex(int num,int flag,int flow):num(num),flag(flag),flow(flow){ // u.push_back(0); x.push_back(0);
}
};
int N; //边数
vector<vertex>v;
public:
Graph(int n):N(n)
{
for(int i=0;i<=n;i++)
{
vertex tmp(i,0,0);
v.push_back(tmp);
for(int j=0;j<=n;j++)
{
v[i].u.push_back(0);
v[i].x.push_back(0);
}
}
v[1].flag=-1; //源点标记为-1
v[1].flow=MAX;
}
void Edge_flow(int i,int j,int flow)
{ v[i].f_edge.push_back(j);
v[i].u[j]=flow;
v[j].b_edge.push_back(i);
}
int Max_flow()
{
queue<int>Q;
Q.push(1);
int max_f=0;
while(!Q.empty())
{
int i=Q.front();Q.pop();
int l=v[i].flow;
for(unsigned int k=0;k<v[i].f_edge.size();k++)
{
int j=v[i].f_edge[k];
if(v[j].flag==0)
{
int r=v[i].u[j]-v[i].x[j];
if(r>0)
{
l=min(l,r);
v[j].flag=1;v[j].ver=i;v[j].flow=l;
Q.push(j);
}
}
}
for(unsigned int k=0;k<v[i].b_edge.size();k++)
{
int j=v[i].b_edge[k];
if(v[j].flag==0)
{
int r=v[j].x[i];
if(r>0)
{
l=min(l,r);
v[j].flag=-1;v[j].ver=i;v[j].flow=l;
Q.push(j);
}
}
}
if(v[N].flag!=0)
{
int j=N;
max_f+=l;
cout<<"One of the path is :";
while(j!=1)
{
cout<<j<<" from ";
int k=v[j].ver;
if(v[j].flag==1)
v[k].x[j]+=l;
if(v[j].flag==-1)
v[j].x[k]-=l;
j=k;
}
cout<<1<<" and the flow is "<<l<<endl;
while(!Q.empty())
Q.pop();
for(int i=2;i<=N;i++)
v[i].flag=0;
Q.push(1);
}
}
return max_f;
}
void Min_cut()
{
for(int i=1;i<N;i++)
{
if(v[i].flag!=0)
{
for(unsigned int k=0;k<v[i].f_edge.size();k++)
{
int j=v[i].f_edge[k];
if(v[j].flag==0&&v[i].flag!=0)
cout<<"("<<i<<","<<j<<")"<<"; ";
}
}
}
}
};
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int ver;
while(cin>>ver)
{
Graph G(ver);
int edge;
cin>>edge;
int i,j,flow;
while(edge--)
{
cin>>i>>j>>flow;javascript:;
G.Edge_flow(i,j,flow);
}
cout<<"The max_flow is :"<<G.Max_flow()<<endl;
cout<<"One of the min_cut is :";
G.Min_cut();
cout<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}
接下来是in.txt里的测试数据,如下:
6
7
1 2 2
1 4 3
2 5 3
2 3 5
4 3 1
3 6 2
5 6 4
4
5
1 2 100
1 3 10
2 3 100
3 4 10
2 4 1000
6
7
1 2 5
1 3 6
2 5 2
2 4 4
3 4 7
4 6 8
5 6 4
6
8
1 2 2
1 3 7
2 4 3
2 5 4
3 4 4
3 5 2
4 6 1
5 6 5
下面是out.txt的输出结果,如下
One of the path is :6 from 5 from 2 from 1 and the flow is 2
One of the path is :6 from 3 from 4 from 1 and the flow is 1
The max_flow is :3
One of the min_cut is :(1,2); (4,3);
One of the path is :4 from 2 from 1 and the flow is 100
One of the path is :4 from 3 from 1 and the flow is 10
The max_flow is :110
One of the min_cut is :(1,2); (1,3);
One of the path is :6 from 5 from 2 from 1 and the flow is 2
One of the path is :6 from 4 from 2 from 1 and the flow is 3
One of the path is :6 from 4 from 3 from 1 and the flow is 3
One of the path is :6 from 4 from 3 from 1 and the flow is 2
The max_flow is :10
One of the min_cut is :(2,5); (4,6);
One of the path is :6 from 4 from 2 from 1 and the flow is 1
One of the path is :6 from 5 from 2 from 1 and the flow is 1
One of the path is :6 from 5 from 3 from 1 and the flow is 2
One of the path is :6 from 5 from 2 from 4 from 3 from 1 and the flow is 1
The max_flow is :5
One of the min_cut is :(1,2); (3,5); (4,6);
可以看到,测试数据是没有问题的,这说明我的代码也应该没有什么问题;再根据分析,广度优先搜索效率是O(nm^2)的,空间消耗是O(n^2).