请加我的微信公众号YWQKirin
最大流问题描述:
在一个有容量限制的网络中,当传送流量时,如何充分利用整个拓扑网络使源点S到汇点T的流量最大。
最大流的特性:
1.网络中只有一个源点和一个汇点,如果有多个或者没有,则构造一个超级源点S和一个超级汇点T出来满足要求。
2.网络是有向网络,如果是无向网络或者混合网络,应该转化成有向网络。
3.网络中的各条弧都有一个权值。
Ford和Fokson算法:
核心思想:通过引进剩余网络,增光路等概念。把问题转化为给一个初值,不断的递增流量,直到达到最优解。每次找到一个增光路,路径的流量必定存在,这样迭代下去总会找到最大流量。
时间复杂度:
因为每次找增光路的复杂度是O(m),而网络中的最大流量不超过是(n-1)U。几最终复杂度是O(nmU)。
对于HDU3549采用邻接矩阵的代码如下:
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
const int MN=50;//最大的顶点数
const int INF=0x3fffffff;
//N顶点数,M边数,SS源点,TT汇点
int N,M,SS,TT;
struct Node
{
int c,f;//c是容量,f是流量
}edge[MN][MN];
//pre是记录搜索路径时记录前一个节点的。
//vis是标记搜索过程中那些节点被搜索到
//que队列
int pre[MN],vis[MN],que[MN],qs,qe;
bool BFS()
{
int u,i;
memset(pre,-1,sizeof(pre));memset(vis,0,sizeof(vis));
qs=0;qe=0; que[qe++]=SS;
while(qs<qe)
{
u=que[qs++];
if(u==TT) return 1;
//可能要改i<=TT,这里要看自己怎么建图,这里假设汇点是顶点号最大
for(i=1;i<=TT;i++)//遍历与u相邻的所有顶点
{
if(0x00==vis[i])
{
if(edge[u][i].c>edge[u][i].f)//正向流量 可以扩展
{
vis[i]=1; que[qe++]=i;
pre[i]=u;
}
else if(edge[i][u].f>0)//反向流量 可以扩展
{
vis[i]=1; que[qe++]=i;
pre[i]=u;
}
}
}
}
return 0;
}
int max_flow()
{
int u,mn,ans=0;
while(BFS()) //用BFS去搜索一条增广路
{
mn=INF;
for(u=TT;u!=SS;u=pre[u])//找当前路径上最小的流量
{
if(edge[pre[u]][u].c>edge[pre[u]][u].f)//是正向流量
{
if(mn>edge[pre[u]][u].c-edge[pre[u]][u].f)
mn=edge[pre[u]][u].c-edge[pre[u]][u].f;
}
else if(edge[u][pre[u]].f>0)//是反向流量
{
if(mn>edge[u][pre[u]].f)
mn=edge[u][pre[u]].f;
}
}
for(u=TT;u!=SS;u=pre[u])//更新当前路径上的流量
{
if(edge[pre[u]][u].c>edge[pre[u]][u].f)
{
edge[pre[u]][u].f+=mn;
}
else if(edge[u][pre[u]].f>0)
{
edge[u][pre[u]].f-=mn;
}
}
ans+=mn;
}
return ans;
}
void Read_Build()
{
int i,u,v,c;
scanf("%d%d",&N,&M);
memset(edge,0,sizeof(edge));//一定要初始化
for(i=0;i<M;i++)
{
scanf("%d%d%d",&u,&v,&c);
edge[u][v].c+=c;
}
SS=1;TT=N;
}
int main()
{
int test,cas=1;scanf("%d",&test);
while(test--)
{
Read_Build();
printf("Case %d: %d\n",cas++,max_flow());
}
return 0;
}