km算法
网络流 km算法
什么是网络流?
网络流指,存在一个源点s和一个汇点t的特殊有向无环图(TAG),虽然说有图会好很多但是毕竟我只是写着为了之后忘了有回顾的东西,而且好麻烦..
那什么是网络流的最大流?
网络流的最大流是指这个网络流允许通过的最大流(有点重复定义的感觉,不过定义好像也是望文生义)
网络流的km算法用于解决网络流的最大流问题
km算法
那怎么解决这个问题呢,参考二分图中增广路的想法。假如从源点bfs发现可以到达汇点,说明这是一条可以被开发的路,那么ans就要加上这个路径中所有边的容量最小值(短板效应)
但是很明显,怎么可能一bfs就bfs成最优规划?bfs肯定会导致某些本不该流的边有流量,又或者本应该流的边在别的边的影响下流量枯竭(联通大王卡,限速又限流,真香)
所以就需要引入一个反悔机制,让路径有删除流量的可能,为此:
在原来的一条边之外(u->v),引入一条反边(v->u),翻边的权值为u,v之间的容量减去正边的流量,即已经在这条边上流过的流量,也可以理解为可以反悔的容量
到此为之,算法就有了雏形:
1.不断bfs判断是否存在增广路,若不存在,说明当前已达到了最大流
2.若存在,就需要从容量中,把这些流量减去
3.对于经过的所有边,正边的容量减去该容量,意为剩余流量减少,对于所有反边,加上该容量,意为可以返回的边增加
4.ans+=流量
代码也是相当易懂个蛋
int BFS(int src,int des)
{
int i,j;
while(!myqueue.empty()) //队列清空
myqueue.pop();
for(i=1;i<m+1;++i)
{
pre[i]=-1;
}
pre[src]=0;
flow[src]= maxData;
myqueue.push(src);
while(!myqueue.empty())
{
int index = myqueue.front();
myqueue.pop();
if(index == des) //找到了增广路径
break;
for(i=1;i<m+1;++i)
{
if(i!=src && capacity[index][i]>0 && pre[i]==-1)
{
pre[i] = index; //记录前驱
flow[i] = min(capacity[index][i],flow[index]); //关键:迭代的找到增量
myqueue.push(i);
}
}
}
if(pre[des]==-1) //残留图中不再存在增广路径
return -1;
else
return flow[des];
}
int maxFlow(int src,int des)
{
int increasement= 0;
int sumflow = 0;
while((increasement=BFS(src,des))!=-1)
{
int k = des; //利用前驱寻找路径
while(k!=src)
{
int last = pre[k];
capacity[last][k] -= increasement; //改变正向边的容量
capacity[k][last] += increasement; //改变反向边的容量
k = last;
}
sumflow += increasement;
}
return sumflow;
}
至此 o( ̄▽ ̄)o