费用流模板 ek+spfa和 dinic+spfa

ek+spfa

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int first[5005],cnt=0;
int n,m,s,t,dis[5005],vis[5005],pre[10005];
struct Edge
{
    int u,v,w,val,next,flow;
}edge[100005];
void init()
{
    cnt=0;
    memset(first,-1,sizeof(first));
}
inline void add(int u,int v,int w,int val)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;//编号为cnt的边的最大流量
    edge[cnt].val=val;//编号为cnt的单位花费
    edge[cnt].flow=0;//编号为cnt的边流量的使用量
    edge[cnt].next=first[u];
    first[u]=cnt++;
}
bool spfa()
{
    queue<int> q;
    memset(vis,0,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    vis[s]=1;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=first[x];i!=-1;i=edge[i].next)
        {
            int lv=edge[i].v;
            if(edge[i].w>edge[i].flow&&dis[lv]>dis[x]+edge[i].val)
            {
                dis[lv]=dis[x]+edge[i].val;
                pre[lv]=i;//保存前驱
                if(!vis[lv])
                {
                    vis[lv]=1;
                    q.push(lv);
                }
            }
        }
    }
    if(dis[t]!=inf)
    {
        return true;
    }
    return false;
}
int ek(int &flow)
{
    int ans=0;
    while(spfa())
    {
        int mint=inf;
        for(int i=t;i!=s;i=edge[pre[i]].u)
        {
            mint=min(mint,edge[pre[i]].w-edge[pre[i]].flow);//寻找最小流量
        }
        for(int i=t;i!=s;i=edge[pre[i]].u)
        {
            edge[pre[i]].flow+=mint;
            edge[pre[i]^1].flow-=mint;
        }
        flow+=mint;
        ans+=(dis[t]*mint);
    }
    return ans;
}
int main()
{
  while(scanf("%d%d%d%d",&n,&m,&s,&t)!=EOF)
  {
    init();
    int x,y,z,w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&y,&z,&w);
        add(x,y,z,w);
        add(y,x,0,-w);
    }
    int maxflow=0;
    int mincost=ek(maxflow);
    printf("%d %d\n",maxflow,mincost);
  }

    return 0;
}

dinic+spfa

int head[100005], ct=1, cur[100005];
int n, m, s, t, maxflow, mincost, dis[100005], f[100005];
const int INF = 0x3f3f3f3f;

struct Edge{
    int u, v, next,f, w;
}e[1000005];

void add(int a, int b, int f, int w){  //加边
    e[++ct].u=a, e[ct].v=b, e[ct].f=f, e[ct].w=w, e[ct].next=head[a], head[a]=ct;
    e[++ct].u=b, e[ct].v=a, e[ct].f=0, e[ct].w=-w, e[ct].next=head[b], head[b]=ct;
}
void init()
{
    ct=1;
    memset(head,-1,sizeof(head));
}

bool spfa()
{
    queue<int> q;
    q.push(s);
    memset(dis, INF, sizeof(dis) );
    dis[s] = 0;
    int u;
    while(!q.empty()){
        u = q.front();
        q.pop();
        f[u] = 0;
        for(int i=head[u];i!=-1; i=e[i].next)
        {
            if(e[i].f && dis[u]+e[i].w<dis[e[i].v])
            {
                dis[e[i].v] = dis[u]+e[i].w;
                if(!f[e[i].v])
                    q.push(e[i].v), f[e[i].v] = 1;
            }
        }
    }
    return dis[t] != INF;
}
int dfs(int u, int flow)
{
    if(u == t) //达到汇点更新最大流
    {
        maxflow += flow; 
        return flow;
    }  
    int sum = 0; f[u] = 1;  //F[]保证了当出现 0 费用边的时候不会出现两个点之间来回跑的情况
    for(int i=cur[u]; i!=-1; i=e[i].next)
    {
        if(!f[e[i].v] && e[i].f  && dis[e[i].v]==dis[u]+e[i].w)
        {
        	cur[u] = i;  //当前弧优化
            int p = dfs(e[i].v, min(flow-sum, e[i].f));
            sum += p, e[i].f -= p, e[i^1].f += p, mincost += p*e[i].w;  //更新费用
            if(sum == flow) break;
        }
    }
    f[u] = 0;
    return sum;
}
void dinic(){
    while(spfa())
    {
    	memcpy(cur, head, sizeof head);
    	dfs(s, INF);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值