新网络流不止24题

link。不会网络流的可以看我的博客

P2756 飞行员配对问题

二分图最大匹配,没啥好讲的。code

P1251 餐巾计划问题

自然地想到把餐巾当成流量。将每个点和汇点连边,容量为 \(r_i\),这样跑最大流就能保证每个点恰好跑 \(r_i\) 个餐巾;将每个点和源点连边,容量 \(r_i\)。可这样黑心商家就能用脏餐巾了,于是考虑将点 \(u\) 拆成 \(u_{dir}\)\(u_{clr}\)\(s\)\(u_{dir}\) 表示每天会从源点进来 \(r_i\) 个脏餐巾,\(t\)\(u_{clr}\) 表示每天会对汇点汇进去 \(r_i\) 个干净的餐巾。然后将 \(s\)\(u_{clr}\) 连一条容量 \(\inf\) 费用 \(p\) 的边表示买入干净毛巾,\(u_{dir}\)\((u+1)_{dir}\) 连边表示脏毛巾留在第二天,\(u_{dir}\) 连在快洗、慢洗之后的点的 \(clr\) 分点上,费用就是钱,容量 \(\inf\),然后跑最小费用最大流。code

P2764 最小路径覆盖问题

最小路径覆盖集问题,见基础知识博客。code

P1646 happinesss

我们知道这些条件肯定要割掉其中一个,于是统计答案的方式我们改成总数减去割,于是问题转化为最小割问题。考虑将一个点拆成文科和理科,然后源点连文科,理科连汇点,对于每组相邻点,我们建一个新点,让这个新点连代表这两个点,然后这个点根据文理连源汇,这两个点和新点连边,跑最大流就行了。code

P4003 无限之环

神仙题啊啊啊!!!!!!

套路化地,我们可以建超级源汇,黑白染色。然后我们发现不会做。于是我们发现了 qyc 的 PPT

qyc 的 PPT 里写了这么一句话:

匹配!匹配!

这启发我们什么?

我们考虑两个接口对接等价于让两个水管旋到同一个点上。

这又启发我们什么?

拆点!把每个方格拆成他自己、左端点、右端点、上端点、下端点五个点。

然后注意到这些管子里的是水。这启发我们什么?

网络流!!!

然后旋转有代价。这启发我们什么?

费用流!!!

然后大胆建模,没有漏水等价于满流。然后就过了!!!

为什么有的题解写了 300 多行?压压行可以写 100 来行啊。

上!代!码!

#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5, INF = 1e9;
const int dx[] = {0, -1, 0, 1, 0};
const int dy[] = {0, 0, 1, 0, -1};
const int px[] = {0, 3, 4, 1, 2};
//  a  b  c  d  数的二进制表示
//  8  4  2  1  位权
// 左 下 右 上  方向
//  4  3  2  1  编号
int n, m, a[N], head[N], tot = 1, S, T, sum;
struct edge
{
    int v, w, c, nxt;
} e[N];
inline void add(int u, int v, int w, int c)
{
    e[++tot].v = v, e[tot].w = w, e[tot].c = c;
    e[tot].nxt = head[u], head[u] = tot;
}
inline void addedge(int u, int v, int w, int c) { add(u, v, w, c), add(v, u, -w, 0); }
int cur[N], dis[N], mincost, maxflow;
bool vis[N];
queue<int> q;
inline bool spfa()
{
    for (int i = 0; i <= T; i++) dis[i] = INF, vis[i] = false;
    dis[S] = 0, vis[S] = true;
    q.push(S);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].v;
            if (dis[v] > dis[u] + e[i].w && e[i].c)
            {
                dis[v] = dis[u] + e[i].w;
                if (!vis[v]) q.push(v), vis[v] = true;
            }
        }
    }
    return dis[T] != INF;
}
int dfs(int u, int minf)
{
    if (u == T || !minf) return minf;
    int flow = 0, f;
    vis[u] = true;
    for (int i = cur[u]; i; i = e[i].nxt)
    {
        int v = e[i].v;
        cur[u] = i;
        if (!vis[v] && e[i].c && dis[v] == dis[u] + e[i].w)
        {
            f = dfs(v, min(minf, e[i].c));
            if (f) minf -= f, flow += f, e[i].c -= f, e[i ^ 1].c += f, mincost += f * e[i].w;
            if (!minf) return vis[u] = false, flow;
        }
    }
    return vis[u] = false, flow;
}
inline void MCMF()
{
    while (spfa())
    {
        for (int i = 1; i <= T; i++) cur[i] = head[i];
        while (int x = dfs(S, INF)) maxflow += x;
    }
}
inline int num(int i, int j, int op) { return (i - 1) * m + j + op * n * m; }
inline void work(int x, int y, int val)
{
    if ((x + y) & 1)
    {
        addedge(S, num(x, y, 0), 0, INF);
        for (int i = 1; i <= 4; i++)
        {
            int idx = x + dx[i], idy = y + dy[i];
            if (idx < 1 || idx > n || idy < 1 || idy > m) continue;
            addedge(num(x, y, i), num(idx, idy, px[i]), 0, 1);
        }
        for (int i = 1; i <= 4; i++)
            if ((val & (1 << (i - 1)))) addedge(num(x, y, 0), num(x, y, i), 0, 1), ++sum;
        int up = num(x, y, 1), rt = num(x, y, 2), dn = num(x, y, 3), lt = num(x, y, 4);
        switch (val)
        {
        case 1: addedge(up, rt, 1, 1), addedge(up, dn, 2, 1), addedge(up, lt, 1, 1); break;
        case 2: addedge(rt, up, 1, 1), addedge(rt, dn, 1, 1), addedge(rt, lt, 2, 1); break;
        case 4: addedge(dn, up, 2, 1), addedge(dn, lt, 1, 1), addedge(dn, rt, 1, 1); break;
        case 8: addedge(lt, up, 1, 1), addedge(lt, rt, 2, 1), addedge(lt, dn, 1, 1); break;
        case 3: addedge(rt, lt, 1, 1), addedge(up, dn, 1, 1); break;
        case 6: addedge(dn, up, 1, 1), addedge(rt, lt, 1, 1); break;
        case 9: addedge(lt, rt, 1, 1), addedge(up, dn, 1, 1); break;
        case 12: addedge(lt, rt, 1, 1), addedge(dn, up, 1, 1); break;
        case 7: addedge(up, lt, 1, 1), addedge(rt, lt, 2, 1), addedge(dn, lt, 1, 1); break;
        case 11: addedge(up, dn, 2, 1), addedge(rt, dn, 1, 1), addedge(lt, dn, 1, 1); break;
        case 13: addedge(up, rt, 1, 1), addedge(dn, rt, 1, 1), addedge(lt, rt, 2, 1); break;
        case 14: addedge(rt, up, 1, 1), addedge(lt, up, 1, 1), addedge(dn, up, 2, 1); break;
        }
    }
    else
    {
        addedge(num(x, y, 0), T, 0, INF);
        for (int i = 1; i <= 4; i++)
            if ((val & (1 << (i - 1)))) addedge(num(x, y, i), num(x, y, 0), 0, 1), ++sum;
        int up = num(x, y, 1), rt = num(x, y, 2), dn = num(x, y, 3), lt = num(x, y, 4);
        switch (val)
        {
        case 1: addedge(rt, up, 1, 1), addedge(dn, up, 2, 1), addedge(lt, up, 1, 1); break;
        case 2: addedge(up, rt, 1, 1), addedge(lt, rt, 2, 1), addedge(dn, rt, 1, 1); break;
        case 4: addedge(up, dn, 2, 1), addedge(lt, dn, 1, 1), addedge(rt, dn, 1, 1); break;
        case 8: addedge(up, lt, 1, 1), addedge(dn, lt, 1, 1), addedge(rt, lt, 2, 1); break;
        case 3: addedge(lt, rt, 1, 1), addedge(dn, up, 1, 1); break;
        case 6: addedge(up, dn, 1, 1), addedge(lt, rt, 1, 1); break;
        case 9: addedge(rt, lt, 1, 1), addedge(dn, up, 1, 1); break;
        case 12: addedge(rt, lt, 1, 1), addedge(up, dn, 1, 1); break;
        case 7: addedge(lt, rt, 2, 1), addedge(lt, up, 1, 1), addedge(lt, dn, 1, 1); break;
        case 11: addedge(dn, up, 2, 1), addedge(dn, lt, 1, 1), addedge(dn, rt, 1, 1); break;
        case 13: addedge(rt, up, 1, 1), addedge(rt, dn, 1, 1), addedge(rt, lt, 2, 1); break;
        case 14: addedge(up, rt, 1, 1), addedge(up, lt, 1, 1), addedge(up, dn, 2, 1); break;
        }
    }
}
int main()
{
    cin.tie(0)->sync_with_stdio(false);
    cout.tie(0);
    cin >> n >> m;
    S = n * m * 5 + 1, T = S + 1;
    for (int i = 1, val; i <= n; i++)
        for (int j = 1; j <= m; j++) cin >> val, work(i, j, val);
    MCMF();
    if (maxflow * 2 != sum) cout << -1;
    else cout << mincost;
    return 0;
}

也不长啊。

posted @ 2024-12-07 11:35  lhc0707  阅读(11)  评论(0编辑  收藏  举报