网络流之最大流

网络流之最大流

EK算法(SAP)

基于增广路的算法,复杂度为 O ( V ∗ E 2 ) O(V*E^2) O(VE2)

找了好久网上的板子,感觉比kuangbin的好理解一些,以后就留着自己用蜡

int g[maxn][maxn];//容量
int f[maxn][maxn];//流量
int pre[maxn];
bool vis[maxn];
bool bfs(int sx,int ex)
{
    mem(pre,-1);
    mem(vis,false);
    queue<int> q;
    vis[sx]=true;
    q.push(sx);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        rep(i,1,n)
        {
            if (!vis[i]&&g[u][i]>0)
            {
                vis[i]=true;
                pre[i]=u;
                if (i==ex)return true;
                q.push(i);
            }
        }
    }
    return false;
}
int solve(int sx,int ex)//sx为起点,ex为终点
{
    int maxflow=0,u,d;
    while(bfs(sx,ex))
    {
        u=ex;
        d=INF;
        while(u!=sx)
        {
            d=min(d,g[pre[u]][u]);
            u=pre[u];
        }
        maxflow+=d;
        u=ex;
        while(u!=sx)
        {
            g[pre[u]][u]-=d;
            g[u][pre[u]]+=d;
            if (f[u][pre[u]]>0)f[u][pre[u]]-=d;
            else f[pre[u]][u]+=d;
            u=pre[u];
        }
    }
    return maxflow;
}





例题1:POJ1273
(补充一下:还有一道模板题:HDU3549)

一个最简单的流量网络,问最大流量。
唯一需要注意的是边可能会有重复。
代码:

const int maxn=4e2+7;
const int INF=1e9;
const ll INFF=1e18;
int g[maxn][maxn];//容量
int f[maxn][maxn];//流量
int pre[maxn];
bool vis[maxn];
int n,m,a,b,c;
bool bfs(int sx,int ex)
{
    mem(pre,-1);
    mem(vis,false);
    queue<int> q;
    vis[sx]=true;
    q.push(sx);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        rep(i,1,n)
        {
            if (!vis[i]&&g[u][i]>0)
            {
                vis[i]=true;
                pre[i]=u;
                if (i==ex)return true;
                q.push(i);
            }
        }
    }
    return false;
}
int solve(int sx,int ex)
{
    int maxflow=0,u,d;
    while(bfs(sx,ex))
    {
        u=ex;
        d=INF;
        while(u!=sx)
        {
            d=min(d,g[pre[u]][u]);
            u=pre[u];
        }
        maxflow+=d;
        u=ex;
        while(u!=sx)
        {
            g[pre[u]][u]-=d;
            g[u][pre[u]]+=d;
            if (f[u][pre[u]]>0)f[u][pre[u]]-=d;
            else f[pre[u]][u]+=d;
            u=pre[u];
        }
    }
    return maxflow;
}
int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        if (n==0&&m==0)break;
        mem(f,0);mem(g,0);
        rep(i,1,m)
        {
            scanf("%d%d%d",&a,&b,&c);
            g[a][b]+=c;
        }
        W(solve(1,n));
    }
    return 0;
}





例题2:POJ1459

题意理解起来真的恶心我吐了
一共有三种形式的东西:
发电站,它不会消耗电能;
用户,它不会产生电能;
最后一种,它既不会产生电也不会消耗电。(当普通结点处理
现在问你最多这个网络能消耗多少的电量。

题解:可以建立一个超级节点n,连往每一个用户,每一个用户和它之间的容量是他消耗的电能
再建立一个超级节点n+1,连往每一个发电站,每一个发电站和它之间的容量是他产生的电能

之前没看清题,结点标号是 [ 0 , n − 1 ] [0,n-1] [0,n1],一开始建立了一个标号为0的超级节点,就一直错

代码:

const int maxn=2e2+7;
const int INF=1e9;
const ll INFF=1e18;
int g[maxn][maxn];
int f[maxn][maxn];
int pre[maxn];
bool vis[maxn];
int n,np,nc,m,a,b,c;
bool bfs(int sx,int ex)
{
    mem(pre,-1);
    mem(vis,false);
    queue<int> q;
    vis[sx]=true;
    q.push(sx);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        rep(i,0,n+1)
        {
            if (!vis[i]&&g[u][i]>0)
            {
                vis[i]=true;
                pre[i]=u;
                if (i==ex)return true;
                q.push(i);
            }
        }
    }
    return false;
}
int solve(int sx,int ex)
{
    int maxflow=0,u,d;
    while(bfs(sx,ex))
    {
        u=ex;
        d=INF;
        while(u!=sx)
        {
            d=min(d,g[pre[u]][u]);
            u=pre[u];
        }
        maxflow+=d;
        u=ex;
        while(u!=sx)
        {
            g[pre[u]][u]-=d;
            g[u][pre[u]]+=d;
            if (f[u][pre[u]]>0)f[u][pre[u]]-=d;
            else f[pre[u]][u]+=d;
            u=pre[u];
        }
    }
    return maxflow;
}
int main()
{
    while(~scanf("%d%d%d%d",&n,&np,&nc,&m))
    {
        mem(f,0);mem(g,0);
        rep(i,1,m)
        {
            scanf(" (%d,%d)%d",&a,&b,&c);
            if (a==b)continue;
            g[a][b]+=c;
        }
        rep(i,1,np)
        {
            scanf(" (%d)%d",&a,&b);
            g[n][a]+=b;
        }
        rep(i,1,nc)
        {
            scanf(" (%d)%d",&a,&b);
            g[a][n+1]+=b;
        }
        W(solve(n,n+1));
    }
    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值