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]中的点,那么这条边为所有割集中包含的边
(博主比较弱,无法具体证明的话,只能直接用结论了)
代码区
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }