• 1797: [Ahoi2009]Mincut 最小割


    1797: [Ahoi2009]Mincut 最小割

    链接

    分析:

      题意为:问一条边是否可能存在于最小割中,是否一定存在于最小割中。

      首先最小割的边一定是满流的边。且这条边点两个端点u.v中,至少一个与S或T联通。而且在残量网络中u->v没有增广路。如果存在增广路,那么会使最小割的增加。这条增广路会和u->v的反向边构成强连通分量。所以一条边可能存在于最小割中,要满足:满流, 残量网络中u,v不属于一个强连通分量。

      那么第二问就是要求S一定可以到u,v一定可以到T。此时如果存在这样的一条路径,会和S->u的反向边构成强连通分量,于是一条边一定存在于最小割中,满足:满流,残量网络中S和u属于同一个强连通分量,v和T属于同一个强连通分量。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long LL;
     
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
     
    const int N = 4005, INF = 1e9;
    struct Edge { int fr, to, nxt, cap; } e[200005]; 
    int head[N], cur[N], dis[N], q[N], low[N], dfn[N], sk[N], bel[N];
    int Index, top, S, T, En = 1, n, m, cnt;
    bool vis[N];
     
    inline void add_edge(int u,int v,int w) {
        ++En; e[En].fr = u, e[En].to = v, e[En].cap = w, e[En].nxt = head[u]; head[u] = En;
        ++En; e[En].fr = v, e[En].to = u, e[En].cap = 0, e[En].nxt = head[v]; head[v] = En;
    }
    bool bfs() {
        for (int i = 1; i <= n; ++i) cur[i] = head[i], dis[i] = -1;
        int L = 1, R = 0;
        q[++R] = S; dis[S] = 0;
        while (L <= R) {
            int u = q[L ++];
            for (int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if (dis[v] == -1 && e[i].cap > 0) {
                    dis[v] = dis[u] + 1; q[++R] = v;
                    if (v == T) return true;
                }
            }
        }
        return false;
    }
    int dfs(int u,int flow) {
        if (u == T) return flow;
        int used = 0, tmp;
        for (int &i = cur[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (dis[v] == dis[u] + 1 && e[i].cap > 0) {
                tmp = dfs(v, min(flow - used, e[i].cap));
                if (tmp > 0) {
                    used += tmp; e[i].cap -= tmp; e[i ^ 1].cap += tmp;
                    if (used == flow) break;
                }
            }
        }
        if (used != flow) dis[u] = -1;
        return used;
    }
    int dinic() {
        int ans = 0;
        while (bfs()) ans += dfs(S, INF);
        return ans;
    }
    void tarjan(int u) {
        low[u] = dfn[u] = ++Index; 
        sk[++top] = u, vis[u] = 1;
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (e[i].cap) {
                if (!dfn[v]) {
                    tarjan(v);
                    low[u] = min(low[u], low[v]);
                }
                else if (vis[v]) low[u] = min(low[u], dfn[v]);
            }
        }
        if (low[u] == dfn[u]) {
            ++cnt;
            do {
                bel[sk[top]] = cnt;
                vis[sk[top]] = false;
                top --;
            } while (sk[top + 1] != u);
        }
    }
    int main() {
        n = read(), m = read(); S = read(), T = read();
        for (int i = 1; i <= m; ++i) {
            int u = read(), v = read(), w = read();
            add_edge(u, v, w);
        }
        dinic();
        for (int i = 1; i <= n; ++i) 
        if (!dfn[i]) tarjan(i);
        for (int i = 2; i <= En; i += 2) {
            if (e[i].cap > 0) puts("0 0");
            else {
                printf(bel[e[i].fr] != bel[e[i].to] ? "1 " : "0 ");
                puts(bel[e[i].fr] == bel[S] && bel[e[i].to] == bel[T] ? "1" : "0");
            }
        }
        return 0;
    }
  • 相关阅读:
    对中级 Linux 用户有用的 20 个命令
    对 Linux 新手有用的 20 个命令
    有趣的JavaScript原生数组函数
    编写更好的CSS
    一套名企WEB前端面试题,不提供答案
    探索JavaScript中Null和Undefined的深渊
    30个你必须记住的CSS选择符
    揭秘JavaScript中谜一样的this
    2013年JavaScript开发人员调查结果
    给HTML初学者的三十条最佳实践
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10486597.html
Copyright © 2020-2023  润新知