HYSBZ 1797 Mincut 最小割

守給你的承諾、 提交于 2019-11-27 13:42:39

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 所在强连通分量中的点,那么这条边为所有割集中包含的边

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

代码区

#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\n");            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\n");                else                    printf("0\n");            }        }    }    return 0;}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!