标签:次数 html https 不同的 标记 str nbsp set 起点
上篇文章我们讲解了最大流问题,那什么是最小费用最大流呢?听名字就可以看出,我们要在满足最大流的同时找到达成最大流的最小费用。
对于一个网络流,最大流是一定的,但是组成最大流的费用是可以不同的,这里就有了在最大流网络上产生的费用流网络,就有了最小花费问题。
简单来说,就是满足最大流的路径可能有多条,我们要从这多条路径中找到一条花费代价最小的路径。所以最大流是解决这类问题的前提
我们用每条边单位流量的花费作为边权,假如一条合法路径上每条边的花费分别为 c1,c2,.......ck , 并且这条边上的最小流量为flow,
那么这条路径上的花费为 : c1 * flow + c2*flow + ..... + ck*flow = (c1+ c2 + c3 + .... + ck)*flow = dis [ci] * flow
这里的 dis[ci] 就是我们要求的最短路!
1、注意超级源点和超级终点的建立。这里的超级源点/汇点的建立是把所有边统一起来,构成一张网络图,因为有些题目不会直接给你网络图,
需要你自己去建立,例如 hdu 1533
2、初始化时,正向边的单位流量费用为cost[u][v],那么反向边的单位流量费用就为 -cost[u][v]。正向边和反向边的费用互为相反数,因为回流费用减少。
3、费用cost数组和容量cap数组每次都要初始化为0。
4、求解从源点到汇点的“最短”路径时,由于网络中存在负权边,因此使用SPFA来实现。
int cap[500][500],cost[500][500],flow[500][500];//cap是容量,cost是花费,flow是流量 int pre[500],dis[500],vis[500],cnt[500];//pre是记录增广路的前驱节点,dis[i]是记录源点到节点i的最小距离 //vis[i]标记点是否在队列中,cnt[i]记录点i进入队列的次数 int n,m; int st,endd; int mn_cost,mx_flow; int spfa() { for(int i=0;i<n;i++) dis[i]=mx; memset(vis,0,sizeof(vis)); memset(cnt,0,sizeof(cnt)); queue<int>p; p.push(st);//st是起点 vis[st]=1; cnt[st]=1; dis[st]=0; while(!p.empty()) { int now=p.front(); p.pop(); vis[now]=0; for(int i=0;i<n;i++) { if(cap[now][i]>flow[now][i]&&dis[i]>dis[now]+cost[now][i])//这里将费用看成是长度,求源点到汇点的最小距离 { dis[i]=dis[now]+cost[now][i]; pre[i]=now; if(vis[i]==0) { p.push(i); vis[i]=1; cnt[i]++; if(cnt[i]>n) return 0; } } } } if(dis[endd]>=mx) return 0; return 1; } void bfs(int n)//顶点数 { memset(flow,0,sizeof(flow)); mx_flow=0; mn_cost=0; while(spfa()) { int f=mx; for(int i=endd;i!=st;i=pre[i]) f=min(f,cap[pre[i]][i]-flow[pre[i]][i]); for(int i=endd;i!=st;i=pre[i]) { flow[pre[i]][i]+=f; flow[i][pre[i]]-=f; } mn_cost+=dis[endd]*f;
mx_flow+=f; } }
标签:次数 html https 不同的 标记 str nbsp set 起点
原文地址:https://www.cnblogs.com/-citywall123/p/11329508.html