首页 > 其他分享 >【题解】P4126 [AHOI2009]最小割

【题解】P4126 [AHOI2009]最小割

时间:2023-01-13 09:57:41浏览次数:67  
标签:dep AHOI2009 题解 stk int edge maxn low P4126

题意

求最小割和可行边和必须边。

思路

清真,清真,还是 ** 的清真。

考虑可行边的充要条件:

  1. 满流

  2. 不存在另一条 \(u, v\) 间的最短路,即在残量网络上不存在包含 \(u, v\) 的环

根据最小割最大流定理有最小割容量等于最大割流量。

因为跑完一遍最短路之后残量网络中不存在增广路,所以割掉所有满流的边以后 \(S, T\) 一定不连通。

又因为在一条已经增广完的路径上,割掉满流边的代价一定优于非满流边的代价,所以只割满流边一定可以构造出最小割,并且割非满流边一定不是最小割。

如果在一种方案中 \((u, v)\) 满流,但是存在另一条 \(u, v\) 之间的增广路径(环),那么只需要分出一部分流量在这条路径上流一次就可以破坏掉 \((u, v)\) 的满流。

判 2 可以用 tarjan 缩点,如果在同一 scc 中就说明有环。

考虑必须边的充要条件:

  1. 是可行边

  2. 不割掉它一定会导致 \(S, T\) 连通

所以在可行边的基础上特判一下 \(u, v\) 所属的连通分量就行。

具体构造见 题解 P4126 【[AHOI2009]最小割】 orz cmd

时间复杂度 O(飞快)

代码

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int maxn = 4e3 + 5;
const int maxm = 6e4 + 5;
const int maxe = 2e5 + 5;
const int inf = 0x3f3f3f3f;

struct node
{
    int to, nxt, w;
} edge[maxe];

struct item
{
    int u, v, w;
} e[maxm];

int n, m, s, t, cnt = 1;
int head[maxn], bel[maxn];

void add_edge(int u, int v, int w)
{
    edge[++cnt] = (node){v, head[u], w};
    head[u] = cnt;
}

namespace net_flow
{
    int dep[maxn], cur[maxn];

    bool bfs()
    {
        queue<int> q;
        memset(dep, 0, (n + 1) * sizeof(int));
        dep[s] = 1;
        q.push(s);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = edge[i].nxt)
            {
                int v = edge[i].to;
                if (edge[i].w && (!dep[v]))
                {
                    dep[v] = dep[u] + 1;
                    q.push(v);
                }
            }
        }
        return (dep[t] > 0);
    }

    int dfs(int u, int dis)
    {
        if (u == t) return dis;
        for (int &i = cur[u]; i; i = edge[i].nxt)
        {
            int v = edge[i].to;
            if (edge[i].w && (dep[v] == dep[u] + 1))
            {
                int dist = dfs(v, min(dis, edge[i].w));
                if (dist)
                {
                    edge[i].w -= dist, edge[i ^ 1].w += dist;
                    return dist;
                }
            }
        }
        return 0;
    }

    int dinic()
    {
        int ans = 0;
        while (bfs())
        {
            int dis;
            memcpy(cur, head, (n + 1) * sizeof(int));
            while (dis = dfs(s, inf)) ans += dis;
        }
        return ans;
    }
}

namespace tarjan
{
    int cnt = 0, cur = 0;
    int top, stk[maxn];
    int low[maxn], dfn[maxn];
    bool in_stk[maxn];

    void pop(int idx)
    {
        int v = stk[top--];
        in_stk[v] = false;
        bel[v] = idx;
    }

    void tarjan(int u)
    {
        low[u] = dfn[u] = ++cnt;
        stk[++top] = u;
        in_stk[u] = true;
        for (int i = head[u]; i; i = edge[i].nxt)
        {
            if (!edge[i].w) continue;
            int v = edge[i].to;
            if (!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if (in_stk[v]) low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u])
        {
            cur++;
            while (stk[top] != u) pop(cur);
            pop(cur);
        }
    }
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &s, &t);
    for (int i = 1, u, v, c; i <= m; i++)
    {
        scanf("%d%d%d", &u, &v, &c);
        e[i] = (item){u, v, c};
        add_edge(u, v, c);
        add_edge(v, u, 0);
    }
    net_flow::dinic();
    for (int i = 1; i <= n; i++)
        if (!tarjan::dfn[i]) tarjan::tarjan(i);
    for (int i = 1; i <= m; i++)
    {
        if (edge[i << 1].w)
        {
            puts("0 0");
            continue;
        }
        putchar(bel[e[i].u] != bel[e[i].v] ? '1' : '0');
        putchar(' ');
        putchar(((bel[e[i].u] == bel[s]) && (bel[e[i].v] == bel[t])) ? '1' : '0');
        putchar('\n');
    }
    return 0;
}

标签:dep,AHOI2009,题解,stk,int,edge,maxn,low,P4126
From: https://www.cnblogs.com/lingspace/p/p4126.html

相关文章

  • 【题解】P6071 『MdOI R1』Treequery
    海浪尽头的你啊,到底何时归来?额滴就木异象啊……思路清真树论。树论地考虑祖先后代关系,分讨一下。用ST表处理一下\(lca(l,r)=u\):\(u,p\)无祖先后代关系,答案......
  • 洛谷P7792 KRIZA 题解 C++
    洛谷P7792KRIZA题解C++题目概述:题目传送门Sisyphus在一个圆形的房间里,房间内有n扇锁着的门,他有n把钥匙,其中第i把钥匙对应第$v_i$扇门,遇到不匹配的钥匙就放......
  • 【题解】P4899 [IOI2018] werewolf 狼人
    そうやってただ日が暮れるまで語り掛ける本当の言葉题意给定一个有向图和若干询问,每次询问是否存在一条满足条件的路径:端点分别为\(u,v\)前面一段不经过\([1,L......
  • 传递游戏【题解】
    Description毛大神最近在玩一个传递游戏,即有\(N\)个人在做传递物品的游戏,这N个人的编号为\(1,2,3,...,N-1,N\)。游戏规则是这样的:开始时物品可以在任意一人手上,他可把物......
  • 表达式的值【题解】
    [NOIP2011普及组]表达式的值题目描述对于1位二进制变量定义两种运算:运算的优先级是:先计算括号内的,再计算括号外的。“×”运算优先于“⊕”运算,即计算表达式......
  • [NOIP2017 普及组]跳房子 【题解】
    题目背景NOIP2017普及组T4题目描述跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。跳房子的游戏规则如下:在地面上确定一个起点,然后在起点......
  • 洛谷 P8077 [WC2022] 序列变换 题解
    题目链接。WC2023之前补一下WC2022的题,参考了官方题解。首先,把括号序列转化为二叉树,\(\texttt{(A)B}\)转为一个点的左子树是\(A\),右子树是\(B\)。相当于括号序列先......
  • 1.8模拟赛题解
    T1考虑每次反弹后,球的运动轨迹都会偏移\(2\beta\),总偏移量即为\(2k\beta\),而最后需要回到原点,因此\(360|2k\beta\),简单求\(\gcd\)即可。T2设\(ans_k\)表示出现过......
  • 1.11模拟赛题解
    T1对于方阵\(A\),考虑其反方阵\(A'\)。容易发现\(A\)与\(A'\)的权值和相同,而其中必有一个与\(B\)的差不超过\(\lfloor\frac{nm}{2}\rfloor\),因此判断一下哪个满足......
  • 1.9模拟赛题解
    T1从左到右扫描,首先如果\(a_i<b_i\)那么一定无解,否则不断在其右边找最近的\(j\)使得\(a_j\in[b_i,a_i]\),把\(a_i\)和\(a_j\)交换。感性理解这是对的。T2先证操......