【NOIP考前题目回顾】Luogu P1001

思路

最大流。建一个超级源点和超级汇点,然后从源点连出两条边,流量分别为a和b,最后将这两个定点分别向汇点连一条流量为无穷大的边,求得的最大流即为答案。

代码

#include <cctype>
#include <climits>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>

#define BLA(X) int X[100001] = { 0 }
BLA(HEAD);
BLA(NEX);
BLA(PRE);
BLA(V);
BLA(USED);
bool VIS[100001] = { 0 };
BLA(LIS);

int S, T;

int tot = 0;
void INS(const int x, const int y, const int v)
{
    tot++;
    LIS[tot] = y;
    NEX[tot] = HEAD[x];
    HEAD[x] = tot;
    V[tot] = v;
}

void INSERT(const int x, const int y, const int v)
{
    INS(x, y, v);
    INS(y, x, 0);
}

bool bfs(const int S)
{
    std::queue<int> q;
    q.push(S);
    std::memset(PRE, 0xff, sizeof PRE);
    PRE[S] = 1;
    while (!q.empty())
    {
        int x = q.front();
        q.pop();
        for (int t = HEAD[x]; t; t = NEX[t])
            if (PRE[LIS[t]] == -1 && V[t])
            {
                PRE[LIS[t]] = PRE[x] + 1;
                q.push(LIS[t]);
            }
    }
    if (PRE[T] == -1)
        return false;
    return true;
}

int dfs(const int pos, const int flow)
{
    if (pos == T)
        return flow;
    int w, t, used = 0;
    for (int t = HEAD[pos]; t; t = NEX[t])
    {
        if (V[t] && PRE[LIS[t]] == PRE[pos] + 1)
        {
            w = dfs(LIS[t], std::min(flow - used, V[t]));
            used += w;
            V[t] -= w;
            V[t + 1] += w;
            if (used == flow)
                return flow;
        }
    }
    if (!used)
        PRE[pos] = -1;
    return used;
}

int DINIC(const int S)
{
    int ans = 0;
    while (bfs(S))
        ans += dfs(S, INT_MAX);
    return ans;
}

int main(int argc, char **argv)
{
    int x, y;
    std::cin >> x >> y;
    INSERT(1, 2, x);
    INSERT(1, 3, y);
    INSERT(2, 4, x);
    INSERT(3, 4, y);
    S = 1;
    T = 4;
    std::cout << DINIC(1) << std::endl;
#ifdef __EDWARD_EDIT
    std::cin.get();
    std::cin.get();
#endif
    return 0;
}
点赞