zoukankan      html  css  js  c++  java
  • 洛谷 P4126 [AHOI2009]最小割

    A,B两个国家正在交战,其中A国的物资运输网中有(N)个中转站,(M)条单向道路。设其中第(i (1≤i≤M))条道路连接了(v_i,u_i)两个中转站,那么中转站(v_i)可以通过该道路到达(u_i)中转站,如果切断这条道路,需要代价(c_i)

    现在B国想找出一个路径切断方案,使中转站(s)不能到达中转站(t),并且切断路径的代价之和最小。

    小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题:

    • 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断?
    • 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断?

    现在请你回答这两个问题。

    最小割的可行边和必须边
    然而做这道题的时候并不会这东西QAQ
    首先我们考虑((u,v))是可行边需要满足的条件

    • 满流
    • 在残余网络u和v不连通

    满流就不用说了,如果u和v连通的话那么这个图也是连通的,就不是最小割了
    然后考虑((u,v))是必须边需要满足的条件

    • 满流
    • 在残余网络中u和起点s连通,v和终点t连通

    我们思考第二个条件,如果u和s不连通或者v和t连通,那么在单独的路径上一定会存在一条可行边,这个割掉和((u,v))割掉是等效的,就不是必须边了
    所以我们可以直接对残余网络做tarjan,可行边需要满足u和v不在同一个强连通分量,必须边满足u和s在同一个强连通分量,v和t在同一个强连通分量
    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 4000;
    const int M = 6e4;
    const int inf = 1e9;
    using namespace std;
    int id[M + 5],co_cnt,co[M + 5],n,m,s,t,dep[M + 5],cur[M + 5],head[M + 5],nxt[M * 2 + 5],q[M + 5],ans,edge_cnt = 1,U[M + 5],V[M + 5],dfn[M + 5],dfn_cnt,low[M + 5],stk[M + 5],top;
    struct edges
    {
        int to,cost;
    }edge[M * 2 + 5];
    int dfs(int u,int flow)
    {
        if (u == t) 
            return flow;
        int sum = 0;
        for (int &i = cur[u];i;i = nxt[i])
        {
            int v = edge[i].to,w = edge[i].cost;
            if (dep[v] == dep[u] + 1 && w)
            {
                int res = dfs(v,min(flow,w));
                edge[i].cost -= res;
                edge[i ^ 1].cost += res;
                sum += res;
                flow -= res;
                if (!flow)
                    return sum;
            }
        }
        if (!sum)
            dep[u] = 0;
        return sum;
    }
    int bfs()
    {
        for (int i = 1;i <= n;i++)
            dep[i] = 0,cur[i] = head[i];
        dep[s] = 1;
        int l = 1,r = 0;
        q[++r] = s;
        while (l <= r)
        {
            int u = q[l++];
            if (u == t) 
                return 1;
            for (int i = head[u];i;i = nxt[i])
            {
                int v = edge[i].to,w = edge[i].cost;
                if (!dep[v] && w)
                {
                    dep[v] = dep[u] + 1;
                    q[++r] = v;
                }
            }
        }
        return 0;
    }
    void add_edge(int u,int v,int w)
    {
        edge[++edge_cnt] = (edges){v,w};
        nxt[edge_cnt] = head[u];
        head[u] = edge_cnt;
    }
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++dfn_cnt;
        stk[++top] = u;
        for (int i = head[u];i;i = nxt[i])
        {
            int v = edge[i].to,w = edge[i].cost;
            if (!w)
                continue;
            if (!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }
            else
                if (!co[v])
                    low[u] = min(low[u],dfn[v]);
        }
        if (low[u] == dfn[u])
        {
            co[u] = ++co_cnt;
            while (stk[top] != u)
                co[stk[top--]] = co_cnt;
            top--;
        }
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&s,&t);
        int w;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d%d%d",&U[i],&V[i],&w);
            add_edge(U[i],V[i],w);
            id[i] = edge_cnt;
            add_edge(V[i],U[i],0);
        }
        while (bfs())
            ans += dfs(s,inf);
        for (int i = 1;i <= n;i++)
            if (!dfn[i])
                tarjan(i);
        for (int i = 1;i <= m;i++)
        {
            if (!edge[id[i]].cost && co[U[i]] != co[V[i]])
                printf("1 ");
            else
                printf("0 ");
            if (!edge[id[i]].cost && co[U[i]] == co[s] && co[V[i]] == co[t])
                printf("1 ");
            else
                printf("0 ");
            putchar(10);
        }
        return 0;
    }
    
  • 相关阅读:
    Web服务技术协议:REST与SOAP
    几种常见的Web服务器
    在浏览器中输入网址后是怎么跳转到指定的服务器的
    forward(请求转发)和redirect(重定向)的区别
    Hook钩子编程
    闭包
    JSP
    临界区与锁
    进程
    LeetCode Search for a Range
  • 原文地址:https://www.cnblogs.com/sdlang/p/13132378.html
Copyright © 2011-2022 走看看