昨天,确切的说应该是今天早上,搞到5点多,调试破了头还是没找出错误原因,早上醒来突发灵感,发现单位费用的边未反向,改后终于AC了,哈哈,开心啊,上阶段的练习算告一段落了。
网络问题基本都是找增广路,再更新,直到某个条件不再满足即停止。
最大流(maxflow),每次找增广路P(augmented path),再找出增广路P中前向弧的最小剩余容量c(通俗点说就是瓶颈),更新各边,剩余网络(residual network)中反向弧要加上c,正向弧减去c,最大流量加上c,直到没有增广路即找到了最大流。
设M为网络中最大边容量,则Ford_Fulkerson算法任何的算法实现复杂度都是O(VM)。
增广路径的查找有好几种选择方式,在图算法书上看到随机测试结果,当容量为1时(如求二分图匹配,二分匹配问题可以归约到最大流问题)最短路径,最大容量,深度优先都差不多。但是当容量1-50随机时,最大容量效率高于最短路径,也远远高于深度优先(差着一个0啊)。
还有预流算法,最高标号预流推进,Relabel_to_Front算法,只做了一般预流,测试了几个题目,实际效率都低于Ford_Fulkerson,难道是我模板写的太差?问队友,都说不这么用到,算了,其它的以后有空再实现了。
最小费用最大流(mincost flow)有个环取消算法(cycle-cancleing algorithm)终止条件是当且仅当剩余网络不再包含负开销有向环,此时的最大流才是一个最小费用最大流。但这个方法得初始化哑边,每次环取消就是尽可能多的将流量移出哑边,但自己没实现过。
我的方法是每次在s-t之间找出费用最小的一条路径即单源最短路,如果t点不再被访问到,则算法终止。否则,按着最短路径找出最小剩余容量c,最大流量加上c,再更新最短路径上的边,前向弧减去c,反向弧加上c,并且造一条逆向的费用边,最小费用加上每条边的花销,每条边的花销=单位费用*c。
最小费用最大流既能求最小费用,又能得出最大流,是更为一般的模型。
附上自己第一次写的代码模板,请教路过的牛人提些建议。

/**//*
网络中求最大流Ford_Fulkerson算法
参数含义: m代表网络中节点数,第1节点为源点, 第m节点为汇点
net[][]代表剩余网络
path[]保存增广路径
neck[]代表瓶颈,保存增广路径最小容量
返回值: 最大流量
*/
const int NMAX = 210;
int net[NMAX][NMAX];
int path[NMAX],n, m;

int bfs()

...{
queue<int> SQ;
int neck[NMAX], i;
memset(path,-1,sizeof(path));
path[1] = 0;
neck[1] = INT_MAX;
SQ.push(1);


while(!SQ.empty()) ...{
int now = SQ.front();
SQ.pop();

if(now == m) ...{
break ;
}

for(i=2;i<=m;i++) ...{

if(net[now][i] > 0 && path[i] == -1) ...{
path[i] = now;
neck[i] = min(neck[now], net[now][i]);
SQ.push(i);
}
}
}

if(path[m] == -1) ...{
return -1;
}
return neck[m];
}

int Ford_Fulkerson()

...{
int now, step;
int max_flow = 0;


while( (step=bfs()) != -1 ) ...{
max_flow += step;
now = m;

while(now != 1) ...{
int pre = path[now];
net[pre][now] -= step;
net[now][pre] += step;
now = pre;
}
}
return max_flow;
}


/**//**** **** **** **** **** ****
网络中最小费用最大流
参数含义: n代表网络中的总节点数
net[][]代表剩余网络
cost[][]代表单位费用
path[]保存增广路径
ecost[]源点到各点的最短路
算法:初始最小费用和最大流均为,寻找单位费用最短路
在最短路中求出最大流,即为增广路,再修改剩余网络,直到无可增广路为止
返回值: 最小费用,最大流量
**** **** **** **** **** ****/
const int NMAX = 210;
int net[NMAX][NMAX], cost[NMAX][NMAX];
int path[NMAX], ecost[NMAX];
int n;
bool bellman_ford()

...{
int i,j;
memset(path,-1,sizeof(path));
fill(ecost, ecost+NMAX, INT_MAX);
ecost[0] = 0;

bool flag = true;

while(flag) ...{
flag = false;

for(i=0;i<=n;i++) ...{

if(ecost[i] == INT_MAX) ...{
continue ;
}

for(j=0;j<=n;j++) ...{

if(net[i][j] > 0 && ecost[i]+cost[i][j] < ecost[j]) ...{
flag = true;
ecost[j] = ecost[i]+cost[i][j];
path[j] = i;
}
}
}
}
return ecost[n] != INT_MAX;
}

int min_cost_max_flow()

...{
int i,j;
int mincost = 0, maxflow = 0;

while( bellman_ford() ) ...{
int now = n;
int neck = INT_MAX;

while(now != 0) ...{
int pre = path[now];
neck = min(neck, net[pre][now]);
now = pre;
}
maxflow += neck;
now = n;

while(now != 0) ...{
int pre = path[now];
net[pre][now] -= neck;
net[now][pre] += neck;
cost[now][pre] = - cost[pre][now];
mincost += cost[pre][now] * neck;
now = pre;
}
}
return mincost;
}
