网络流-最小费用最大流

来源:互联网 发布:基础c语言代码实例 编辑:程序博客网 时间:2024/06/10 04:31

定义

有时,网络中每条边除了容量还有费用。最小费用最大流(MincostMaxflow,简称MCMF)就是在最大流的基础上,费用最小。

实现

和EK类似,最小费用最大流的求法也是暴力寻找增广路,但是不是用Bfs进行增广,而是用Bellman-Ford或者Spfa进行增广。寻找增广路时,先要满足可以增广,然后检查费用是否更优秀,两者都满足,才修正。这样增广下来,不难发现肯定满足费用最小。

这个算法的效率是玄学……但是实际运用中应该可能大概够了吧。

模板

实在没找到模板题,用POJ2135当模板题好了。
因为每条道路只能通过一次,所以我们可以认为每条道路的容量为1,费用为这条道路的长度(由于这道题是双向边,所以必须正反都建边)。但是要走回来怎么办?因为不能重复走,所以走回来就等价于走两次(已双向建边),我们可以增加两个虚拟节点0和n+1:0向1构造一条容量为2,费用为0的边,n向n+1构造一条容量为2,费用为0的边。然后直接刷最小费用最大流即可。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=1000,maxm=40000;int n,m,E,lnk[maxn+5],son[maxm+5],nxt[maxm+5];int que[maxn+5],p[maxn+5],dis[maxn+5],MF[maxn+5];bool vis[maxn+5];struct Edge{    int fa,cap,flow,cost;};Edge e[maxm+5];void Add(int x,int y,int a,int b){    son[E]=y;nxt[E]=lnk[x];lnk[x]=E;e[E].fa=x;e[E].cap=a;e[E].flow=0;e[E].cost=b;E++;    son[E]=x;nxt[E]=lnk[y];lnk[y]=E;e[E].fa=y;e[E].cap=0;e[E].flow=0;e[E].cost=-b;E++;}bool Spfa(int st,int gl,int &MIN,int &MAX){    memset(vis,0,sizeof(vis));memset(dis,63,sizeof(dis));memset(MF,63,sizeof(MF));    int Head=0,Tail=0,INF=dis[0];que[++Tail]=st;vis[st]=true;dis[st]=0;    while (Head!=Tail)    {        int x=que[Head=(Head+1)%maxn];vis[x]=false;        for (int j=lnk[x];~j;j=nxt[j])            if (e[j].cap>e[j].flow&&dis[x]+e[j].cost<dis[son[j]]) //同时满足两个条件            {                dis[son[j]]=dis[x]+e[j].cost;p[son[j]]=j;                MF[son[j]]=min(MF[x],e[j].cap-e[j].flow);                if (!vis[son[j]])                {                    que[Tail=(Tail+1)%maxn]=son[j];vis[son[j]]=true;                    if (dis[que[(Head+1)%maxn]]>dis[que[Tail]])                        swap(que[(Head+1)%maxn],que[Tail]);                }            }    }    if (dis[gl]==INF) return false;    MIN+=dis[gl]*MF[gl];MAX+=MF[gl];    for (int now=gl;now!=st;now=e[p[now]].fa)        e[p[now]].flow+=MF[gl],e[p[now]^1].flow-=MF[gl];    return true;}int MCMF(int s,int t){    int MIN=0,MAX=0;    while (Spfa(s,t,MIN,MAX));    return MIN;}int main(){    freopen("MCMF.in","r",stdin);    freopen("MCMF.out","w",stdout);    scanf("%d%d",&n,&m);memset(lnk,255,sizeof(lnk));    Add(0,1,2,0);Add(n,n+1,2,0);    for (int i=1;i<=m;i++)    {        int x,y,z;scanf("%d%d%d",&x,&y,&z);        Add(x,y,1,z);Add(y,x,1,z);    }    printf("%d\n",MCMF(0,n+1));    return 0;}
1 0
原创粉丝点击