费用流

最小费用最大流(转至Lost(转至威士忌)的代码)

)):

每次在s-t之间找出费用最小的一条路径即单源最短路,如果t点不再被访问到,则算法终止。否则,按着最短路径找出最小剩余容量c,最大流量加上 c,再更新最短路径上的边,前向弧减去c,反向弧加上c,并且造一条逆向的费用边,最小费用加上每条边的花销,每条边的花销=单位费用*c。

最小费用最大流既能求最小费用,又能得出最大流,是更为一般的模型。

 

牛人哈~~~自己也懒得看原理了,代码中使用了bellman-ford算法,貌似可以改进为spfa,会更好。

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/* *** **** **** **** **** ****
网络中最小费用最大流
参数含义: 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;
}

 

spfa+静态邻接表

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/* 存边的时候注意前向弧存在Edge数组的偶数里面,后向弧存在奇数里面,并且相差1 */

#include
< iostream >
#include
< queue >
using namespace std;

#define fmax(a,b) (a>b?a:b)
#define fmin(a,b) (a<b?a:b)
const long inf = 1e9;
const long maxn_edge = 10005 ;
const long maxn_point = 105 ;

int Index;
int n,m;
struct node
{
int to;
int c; // 容量
int w; // 费用
int next;
}Edge[maxn_edge];
int pre[maxn_point];
int dir[maxn_point],path_v[maxn_point],path_e[maxn_point],vis[maxn_point]; // 求最短路
queue < int > Q;

inline
void _insert( int from, int to, int c, int w)
{
Edge[Index].to
= to;
Edge[Index].c
= c;
Edge[Index].w
= w;
Edge[Index].next
= pre[from];
pre[from]
= Index ++ ;
}

void insert( int from, int to, int c, int w)
{
_insert(from,to,c,w);
_insert(to,from,
0 , - w);
}

int Init()
{
// CODE
return 1 ;
}
int min_cost_max_flow( int start, int end)
{
int i;
int min_cost = 0 ,max_flow = 0 ;
while ( true )
{
memset(path_v,
- 1 , sizeof (path_v));
memset(path_e,
- 1 , sizeof (path_e));
memset(vis,
0 , sizeof (vis));
fill(dir,dir
+ maxn_point,inf);

dir[start]
= 0 ;
Q.push(start);
vis[start]
= true ;
while ( ! Q.empty())
{
int x = Q.front();
vis[x]
= false ;
Q.pop();

for (i = pre[x];(i + 1 );i = Edge[i].next)
{
int y = Edge[i].to;
if (Edge[i].c && dir[y] > dir[x] + Edge[i].w)
{
dir[y]
= dir[x] + Edge[i].w;
if ( ! vis[y])
{
vis[y]
= true ;
Q.push(y);
}
path_v[y]
= x,path_e[y] = i;
}
}
}


if (path_v[end] == - 1 ) // dir[end] == inf
break ;

int Min = inf;
for (i = end;i != start;i = path_v[i])
{
Min
= fmin(Min,Edge[path_e[i]].c);
}

max_flow
+= Min;
min_cost
+= Min * dir[end];

for (i = end;i != start;i = path_v[i])
{
Edge[path_e[i]].c
-= Min;
Edge[path_e[i]
^ 1 ].c += Min;
}
}

return min_cost;
}

int main()
{
while (Init())
{
int num = min_cost_max_flow( 1 ,n);
printf(
" %d\n " ,num);
}
return 0 ;
}

 

 

转载于:https://www.cnblogs.com/silencExplode/archive/2011/01/20/1939908.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值