MCMF.docx
- 文档编号:3004317
- 上传时间:2022-11-17
- 格式:DOCX
- 页数:8
- 大小:16.86KB
MCMF.docx
《MCMF.docx》由会员分享,可在线阅读,更多相关《MCMF.docx(8页珍藏版)》请在冰豆网上搜索。
MCMF
最小费用最大流
1)、SPFA(ShortestPathFastAlgorithm)
SPFA是一种单源最短路径算法,所以以下所说的“某点的最短路径长度”,指的是“某点到源点的最短路径长度”。
记源点为S,由源点到达点i的“当前最短路径”为D[i],开始时将所有D[i]初始化为无穷大,D[S]则初始化为0。
算法所要做的,就是在运行过程中,不断尝试减小D[]数组的元素,最终将其中每一个元素减小到实际的最短路径。
算法过程中,我们要维护一个队列,开始时将源点置于队首,然后反复进行这样的操作,直到队列为空:
(1)从队首取出一个结点u,扫描所有由u结点可以一步到达的结点,具体的扫描过程,随存储方式的不同而不同;
(2)一旦发现有这样一个结点,记为v,满足D[v]>D[u]+w(u,v),则将D[v]的值减小,减小到和D[u]+w(u,v)相等。
其中,w(u,v)为图中的边u-v的长度,由于u-v必相邻,所以这个长度一定已知(不然我们得到的也不叫一个完整的图);这种操作叫做松弛。
松弛操作的原理是著名的定理:
“三角形两边之和大于第三边”,在信息学中我们叫它三角不等式。
所谓对i,j进行松弛,就是判定是否d[j]>d[i]+w[i,j],如果该式成立则将d[j]减小到d[i]+w[i,j],否则不动。
(3)上一步中,我们认为我们“改进了”结点v的最短路径,结点v的当前路径长度D[v]相比于以前减小了一些,于是,与v相连的一些结点的路径长度可能会相应地减小。
注意,是可能,而不是一定。
但即使如此,我们仍然要将v加入到队列中等待处理,以保证这些结点的路径值在算法结束时被降至最优。
当然,如果连接至v的边较多,算法运行中,结点v的路径长度可能会多次被改进,如果我们因此而将v加入队列多次,后续的工作无疑是冗余的。
这样,就需要我们维护一个bool数组Inqueue[],来记录每一个结点是否已经在队列中。
我们仅将尚未加入队列的点加入队列。
基于邻接表的源码:
voidSPFA(){
for(inti=1;i<=gv;i++)
Dist[i]=100000;
Dist[S]=0;
intclosed=0,open=1;
queue[1]=S;
Inqueue[S]=true;
do{
closed++;
node*tmp=connect[queue[closed]];
Inqueue[queue[closed]]=false;
while(tmp!
=NULL){
if(Dist[tmp->key]>Dist[queue[closed]]+tmp->w){
Dist[tmp->key]=Dist[queue[closed]]+tmp->w;
Path[tmp->key]=queue[closed];
if(!
Inqueue[tmp->key]){
Inqueue[tmp->key]=true;
open++;
queue[open]=tmp->key;
}
}
tmp=tmp->next;
}
}while(closed } 基于邻接矩阵的源码: voidSPFA(){ for(inti=1;i<=gv;i++){ Dist[i]=100000; for(intj=1;j<=gv;j++) if(! Graph[i][j]&&i! =j)Graph[i][j]=100000; } intclosed=0,open=1; queue[1]=S; Dist[S]=0; do{ closed++; intu=queue[closed]; Inqueue[u]=false; for(inti=1;i<=gv;i++) if(Dist[i]>Dist[u]+Graph[u][i]){ Dist[i]=Dist[u]+Graph[u][i]; Path[i]=u; if(! Inqueue[i]){ Inqueue[i]=true; open++; queue[open]=i; } } }while(closed } 2)、MCMF(MinimumCostMaximunFlow) #include #include #include #include #include usingnamespacestd; constintinf=1<<30; intdemands[55][55]; intsupply[55][55]; intmoney[55][55][55]; intcost[105][105]; intflow[105][105]; intcap[105][105]; intd[105]; intp[105]; intsum[55]; inttotal[55]; boolused[105]; intm,n,c; intMIN(inta,intb) { if(a>b) returnb; returna; } voidSPFA(ints) { intu,v,t=n+m+1; queue memset(used,0,sizeof(used)); memset(p,-1,sizeof(p)); for(u=0;u<=t;u++) d[u]=inf; d[s]=0; q.push(s); used[s]=true; while(! q.empty()) { u=q.front(); q.pop(); used[u]=false; for(v=0;v<=t;v++) { if(cap[u][v]>flow[u][v]&&d[v]>d[u]+cost[u][v]) { d[v]=d[u]+cost[u][v]; p[v]=u; if(! used[v]) { used[v]=true; q.push(v); } } } } } voidMCMF(ints,intt) { inta,u; memset(flow,0,sizeof(flow)); c=0; while (1) { SPFA(s); if(p[t]==-1) break; a=inf; u=t; while(p[u]! =-1) { a=MIN(a,cap[p[u]][u]-flow[p[u]][u]); u=p[u]; } u=t; while(p[u]! =-1) { flow[p[u]][u]+=a; flow[u][p[u]]-=a; u=p[u]; } c+=d[t]*a; } } intmain() { inti,j,k,t,ans,kind,temp; boolflag; while(scanf("%d%d%d",&n,&m,&kind)! =EOF) { if(n==0&&m==0&&kind==0) break; memset(sum,0,sizeof(sum)); memset(total,0,sizeof(total)); flag=true; for(inti=1;i<=n;i++) { for(intj=1;j<=kind;j++) { scanf("%d",&demands[i][j]); sum[j]+=demands[i][j]; } } for(inti=1;i<=m;i++) { for(intj=1;j<=kind;j++) { scanf("%d",&supply[i][j]); total[j]+=supply[i][j]; } } for(intk=1;k<=kind;k++) for(inti=1;i<=n;i++) for(intj=1;j<=m;j++) scanf("%d",&money[k][i][j]); for(intk=1;k<=kind;k++) { if(total[k] { printf("-1\n"); flag=false; break; } } if(! flag) continue; t=m+n+1; ans=0; for(intk=1;k<=kind;k++) { memset(cap,0,sizeof(cap)); memset(cost,0,sizeof(cost)); for(inti=1;i<=m;i++) { for(intj=1;j<=n;j++) { cap[i][j+m]=supply[i][k]; cost[i][j+m]=money[k][j][i]; cost[j+m][i]=-cost[i][j+m]; } } for(inti=1;i<=m;i++) cap[0][i]=supply[i][k]; for(inti=1;i<=n;i++) cap[i+m][t]=demands[i][k]; MCMF(0,t); ans+=c; } printf("%d\n",ans); } return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MCMF