HYSBZ 1797 Mincut 最小割

Descrption

A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。

Input

第一行有4个正整数,依次为N,M,s和t。第2行到第(M+1)行每行3个正 整数v,u,c表示v中转站到u中转站之间有单向道路相连,单向道路的起点是v, 终点是u,切断它的代价是c(1≤c≤100000)。 注意:两个中转站之间可能有多条道路直接相连。 同一行相邻两数之间可能有一个或多个空格。

Output

对每条单向边,按输入顺序,依次输出一行,包含两个非0即1的整数,分 别表示对问题一和问题二的回答(其中输出1表示是,输出0表示否)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

Sample Input

6 7 1 6
1 2 3
1 3 2
2 4 4
2 5 1
3 5 5
4 6 2
5 6 3

Sample Output

1 0
1 0
0 0
1 0
0 0
1 0
1 0

Hint

设第(i+1)行输入的边为i号边,那么{1,2},{6,7},{2,4,6}是仅有的三个最小代价切割方案。它们的并是{1,2,4,6,7},交是 。 【数据规模和约定】 测试数据规模如下表所示 数据编号 N M 数据编号 N M 1 10 50 6 1000 20000 2 20 200 7 1000 40000 3 200 2000 8 2000 50000 4 200 2000 9 3000 60000 5 1000 20000 10 4000 60000

 题目分析

题意:给出一个图,求最小割,随后问图中每一条边是否满足这两个判断:1)该道路是否是某一最小割集中的边,2)该道路是否是所有的最小割集中的边;对于每一条边,输出这个判断的结果。

思路:先跑一遍Dinic,求出最小割,随后用tarjan算法在残余网络中求出所有的强连通分量,用node[i]表示点i所在强连通分量的编号,由于残余网络中没有s-t的通路,因此肯定有 node[s] != node[t],对于两个判断的处理入下:

1)我们将每个残余网络缩成点,如果某个边是满流边,并且边的两端点分属于不同的强连通分量,那么这条边一定是某最小割集中的边

2)如果某条边的两端点分别是 s和 t 所在强连通分量node[s],node[t]中的点,那么这条边为所有割集中包含的边

(博主比较弱,无法具体证明的话,只能直接用结论了)

代码区

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>

#define bug cout << "**********" << endl
#define show(x, y) cout<<"["<<x<<","<<y<<"] "
#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int Max = 1e5 + 10;

struct Edge
{
    int from, to, next, flow;
} edge[Max << 1];

int n, m, s, t;
int head[Max], tot;
int dis[Max];
int dfn[Max], low[Max], time_clock;
int node[Max], ans;
int line[Max], now;

void init()
{
    memset(head, -1, sizeof(head));
    tot = 0;
    memset(node, 0, sizeof(node));
    memset(dfn,0,sizeof(dfn));time_clock = 0;
    now = 0;ans = 0;
}

void add(int u, int v, int flow)
{
    edge[tot].from = u;
    edge[tot].to = v;
    edge[tot].flow = flow;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool bfs()
{
    memset(dis, -1, sizeof(dis));
    queue<int> q;
    q.push(s);
    dis[s] = 0;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (edge[i].flow > 0 && dis[v] == -1)
            {
                dis[v] = dis[u] + 1;
                if (v == t)
                    return true;
                q.push(v);
            }
        }
    }
    return false;
}

int dfs(int u, int flow_in)
{
    if (u == t)
        return flow_in;
    int flow_out = 0;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (dis[v] == dis[u] + 1 && edge[i].flow > 0)
        {
            int flow = dfs(v, min(flow_in, edge[i].flow));
            if (flow == 0)
                continue;
            flow_in -= flow;
            flow_out += flow;
            edge[i].flow -= flow;
            edge[i^1].flow += flow;
            if (flow_in == 0)
                break;
        }
    }
    return flow_out;
}

int Dinic()
{
    int sum = 0;
    while (bfs())
    {
        sum += dfs(s, inf);
    }
    return sum;
}

void tarjan(int u)
{
    dfn[u] = low[u] = ++time_clock;
    line[++now] = u;
    for(int i = head[u] ;i != -1 ;i = edge[i].next)
    {
        int v = edge[i].to;
        if(edge[i].flow > 0)
        {
            if(!dfn[v])
            {
                tarjan(v);
                low[u] =  min(low[u],low[v]);
            }
            else if(!node[v])
            {
                low[u] = min(low[u],dfn[v]);
            }
        }
    }
    if(dfn[u] == low[u])
    {
        ans++;
        while(line[now] != u)
        {
            node[line[now--]] = ans;
        }
        node[line[now--]] = ans;
    }
}

int main()
{
#ifdef LOCAL
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    while(scanf("%d%d%d%d",&n,&m,&s,&t)!=EOF)
    {
        init();
        for(int i = 1, u, v, flow ;i <= m ;i++)
        {
            scanf("%d%d%d",&u,&v,&flow);
            add(u,v,flow);add(v,u,0);
        }
        Dinic();
        for(int i = 1 ;i <= n ;i ++)
            if(!dfn[i]) tarjan(i);

        for(int i = 0 ;i < tot ; i += 2)
        {
            if(edge[i].flow) printf("0 0
");
            else
            {
                if(node[edge[i].from] != node[edge[i].to])
                    printf("1 ");
                else
                    printf("0 ");

                if(node[edge[i].from] == node[s] && node[edge[i].to] == node[t])
                    printf("1
");
                else
                    printf("0
");
            }
        }
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/winter-bamboo/p/11366123.html