ZKW费用流模板

以 LOJ 102 为例

#include <cstdio>
#include <cstring>
#define Min(_A, _B) (_A < _B ? _A : _B)
#define R register
int F()
{
    R int x; R char ch;
    while(ch = getchar(), ch < '0' || ch > '9'); x = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - '0';
    return x;
}
const int MaxN = 410, MaxM = 15010, Inf = 2147483647;
int S, T, pi1, Ans, Sum;
int Point[MaxN], Next[MaxM << 1], To[MaxM << 1], W[MaxM << 1], C[MaxM << 1], q = 1;
void Add(R int u, R int v, R int c, R int w)
{
    Next[++q] = Point[u]; Point[u] = q; To[q] = v; C[q] = c; W[q] = w;
    Next[++q] = Point[v]; Point[v] = q; To[q] = u; C[q] = 0; W[q] = -w;
}
bool vis[MaxN];
bool modlabel()
{
    int d = Inf;
    for(int i = 1; i <= T; ++i) if(vis[i])
      for(int j = Point[i]; j; j = Next[j])
          if(C[j] && !vis[To[j]] && W[j] < d) d = W[j];
    if(d == Inf) return 0;
    for(int i = 1;i <= T; ++i) if(vis[i])
      for(int j = Point[i]; j; j = Next[j])
          W[j] -= d, W[j ^ 1] += d;
    pi1 += d;
    return 1;
}
int agu(R int Now, R int Flow)
{
    vis[Now] = 1;
    if(Now == T) 
    {
        Ans += Flow * pi1;
        return Flow;
    }
    R int tmp, f = Flow;
    for(R int j = Point[Now]; j; j = Next[j])
        if(!vis[To[j]] && C[j] && !W[j] && (tmp = agu(To[j], Min(f, C[j]))))
        {
            C[j] -= tmp;
            C[j ^ 1] += tmp;
            f -= tmp;
            if(f == 0) return Flow;
        }
    return Flow - f;
} 
void zkwMCMF()
{
    do
    {
        R int tmp;
        do
        {
            memset(vis, 0, sizeof(vis));
            tmp = agu(S, Inf);
            Sum += tmp;
        }
        while(tmp); 
    }
    while(modlabel());
}
int main()
{
    R int n, m;
    scanf("%d %d", &n, &m);
    for(R int i = 1; i <= m; i++)
    {
        R int u = F(), v = F(), c = F(), w = F();
        Add(u, v, c, w);
    }
    S = 1, T = n; zkwMCMF();
    printf("%d %d\n", Sum, Ans);
}
//https://artofproblemsolving.com/community/c1368h1020435
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值