模板:Edmonds_Karp 算法

题目见USACO草地排水一题

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
#include<climits>
#include<string>
#include<cstdlib>
#include<set>
#include<stack>
#include<map>
#include<bitset>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline ll read()
{
    char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
    ll x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
    if(k=='-')x=0-x;return x;
}

ll n,m;
struct E
{
    ll edge;
    ll zhi;
    ll s;
}a[3000];
ll last[3000];
ll back;
ll ans;
ll pre[3000];//前驱边在a数组中的位置 
ll prn[3000];//前驱节点 


inline void Edmonds_karp()
{
    while(1)//不停寻找 
    {
        queue<ll>p;//队列用来广度优先搜索 
        ll minflow=INT_MAX;
        p.push(1);
        memset(pre,0,sizeof(pre));
        memset(prn,0,sizeof(prn));
        while(!p.empty())//进行搜索 
        {
            int u=p.front();
            p.pop();
            if(u==n)break;//找到终点就跳出了(已经找到一条增广路径) 
            for(int j=last[u];j;j=a[j].zhi)
            {
                if(a[j].s>0&&prn[a[j].edge]==0)//可行弧且没有访问过 
                {
                    pre[a[j].edge]=j;
                    prn[a[j].edge]=u;
                    p.push(a[j].edge);
                }
            }
        }
        if(prn[n]==0)break;//到达不了终点就结束算法 
        for(int i=n;i!=1;i=prn[i])//找到边最小流量 
        minflow=min(minflow,a[pre[i]].s);
        for(int i=n;i!=1;i=prn[i])//将流量修改在各边 
        {
            ll q=pre[i];
            a[q].s-=minflow;
            a[q^1].s+=minflow;
        }
        ans+=minflow;//找到一条增广路径,增加流量 
    }
}



int main()
{
    //freopen("dt.in","r",stdin);
    //freopen("dt.out","w",stdout);
    m=read();n=read();
    for(int i=1;i<=m;++i)
    {
        ll a1=read(),b1=read(),c1=read(); 
        a[++back].edge=b1;//建立正向边 
        a[back].zhi=last[a1];
        a[back].s=c1;
        last[a1]=back;

        a[++back].edge=a1;//建立逆向边 
        a[back].zhi=last[b1];
        a[back].s=0;
        last[b1]=back;
    }
    Edmonds_karp();//算法 
    cout<<ans<<endl;
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值