最小费用最大流

传送门

这里详(jian)细(dan)解释一下最小费用最大流。
最大流会不会?
会!
最短路会不会?
会!
那你不就会这个题怎么写了。。。
算了,最小费用最大流是要求在最小费用的前提下求最大流,那么我们显然要优先考虑最小费用吗,想想我们求最大流的过程。
我们就可以将费用定成边权,将bfs求增广路变成最短路求增广路,这样就能保证最小费用了,剩下的不就是最大流的事了吗?
zkw费用流

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int tmp=1,sum,n,m,son[200001],ans,nex[200001],h[200001],v[200001],s,t,c[200001],dis[200001],slack[200001];
bool used[200001];
const int inf=1e9;
void ins(int x,int y,int z,int d)
{
    son[++tmp]=y;nex[tmp]=h[x];h[x]=tmp;v[tmp]=d;c[tmp]=z;
    son[++tmp]=x;nex[tmp]=h[y];h[y]=tmp;v[tmp]=-d;c[tmp]=0;
}
int KM(int x,int flow)
{
    if(x==t){sum+=flow*dis[t];return flow;}
    used[x]=1;
    int cp=flow;
    for(int i=h[x];i;i=nex[i])
    {
        int l=son[i];
        if(!used[l]&&c[i])
        {
            if(dis[x]+v[i]-dis[l]==0)
            {
                int y=KM(l,min(c[i],cp));
                cp-=y,c[i]-=y,c[i^1]+=y;
                if(!cp)return flow;
            }
            else slack[l]=min(slack[l],dis[x]+v[i]-dis[l]);
        }
    }
    return flow-cp;
}
bool dfs()
{
    int mx=inf;
    for(int i=1;i<=n;i++)
        if(!used[i])mx=min(mx,slack[i]),slack[i]=inf;
    if(mx==inf)return 1;
    for(int i=1;i<=n;i++)
        if(!used[i])dis[i]+=mx;
    return 0;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1,x,y,z,w;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&y,&z,&w);
        ins(x,y,z,w);
    }
    memset(slack,63,sizeof(slack));
    do{
        do{
        	memset(used,0,sizeof(used));
      	    tmp=KM(s,inf),ans+=tmp;
      	  }while(tmp);
        }while (!dfs());
    printf("%d %d",ans,sum);
}

EK

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
inline void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define min(a,b) (a<b?a:b)
#define rg register
queue<int>q;int n,m,s,t,num,b[200001],c[200001],pre[200001],dis[100010],nxt[200001],h[100010],v[200001],w[200001],cnt=1,inf=1e9,ans,que[200001];bool vis[100010];
inline void add(int x,int y,int z,int u)
{
    pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,v[cnt]=z,w[cnt]=u,
    pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt,v[cnt]=0,w[cnt]=-u;
}
bool spfa(int s)
{
    memset(dis,63,sizeof dis);
    q.push(s),dis[s]=0;
    while(!q.empty())
    {
        int x=q.front();q.pop(),vis[x]=0;
        for(rg int i=h[x];i;i=nxt[i])
            if(v[i]&&dis[pre[i]]>dis[x]+w[i])
            {
                dis[pre[i]]=dis[x]+w[i],b[pre[i]]=x,c[pre[i]]=i;
                if(!vis[pre[i]])vis[pre[i]]=1,q.push(pre[i]);
            }
    }
    return dis[t]<inf;
}
int getans()
{
    int mn=inf;
    for(rg int i=t;i!=s;i=b[i])mn=min(v[c[i]],mn);
    for(rg int i=t;i!=s;i=b[i])v[c[i]]-=mn,v[c[i]^1]+=mn;
    num+=mn;
    return dis[t]*mn;
}
int main()
{
    read(n),read(m),read(s),read(t);
    for(rg int i=1,x,y,z,w;i<=m;i++)read(x),read(y),read(z),read(w),add(x,y,z,w);
    while(spfa(s))ans+=getans();
    printf("%d %d\n",num,ans);
}
posted @ 2019-01-05 10:17  蒟蒻--lichenxi  阅读(120)  评论(0编辑  收藏  举报