Description
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
思路:
求是否有一条边出现在某个最小割中,
求是否有一条边出现在所有最小割中。
在残余网络上跑tarjan求出所有SCC,记id[u]为点u所在SCC的编号。显然有id[s]!=id[t](否则s到t有通路,能继续增广)。
①对于任意一条满流边(u,v),(u,v)能够出现在某个最小割集中,当且仅当id[u]!=id[v];
②对于任意一条满流边(u,v),(u,v)必定出现在最小割集中,当且仅当id[u]==id[s]且id[v]==id[t]。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int INF = 0x3f3f3f3f;
struct node
{
int next,v,w;
}edge[N];
int Head[N],cur[N],dep[N],cnt = 1;
int n,m,s,t;
void ins(int u,int v,int w){
cnt++;
edge[cnt].next = Head[u];
edge[cnt].v = v;
edge[cnt].w = w;
Head[u] = cnt;
}
void init(){
int z,x,y;
// memset(Head,-1,sizeof(Head));
scanf("%d%d%d%d",&n,&m,&s,&t);
for (int i = 1; i <= m; ++i){
scanf("%d%d%d",&x,&y,&z);
ins(x,y,z);
ins(y,x,0);
}
}
bool bfs(){
queue<int>Q;
Q.push(s);
memset(dep,0,sizeof(dep));
dep[s] = 1;
while(!Q.empty()){
int u = Q.front(); Q.pop();
for (int i = Head[u]; i; i = edge[i].next){
int v = edge[i].v;
if (!dep[v] && edge[i].w > 0){
dep[v] = dep[u] + 1;
if (v == t) return 1;
Q.push(v);
}
}
}
if (dep[t]) return 1;
return 0;
}
int dfs(int u, int flow){
if (u == t || flow == 0) return flow;
for (int &i = cur[u]; i; i = edge[i].next){
int v = edge[i].v,w = edge[i].w;
if (dep[v] > dep[u] && w > 0){
int d = dfs(v,min(flow,w));
if (d){
edge[i].w -= d;
edge[i^1].w += d;
return d;
}
}
}
return 0;
}
void Dinic(){
int ans = 0;
while(bfs()){
for (int i = 1; i <= n; ++i)
cur[i] = Head[i];
int d = dfs(s,INF);
while(d){
ans += d;
d = dfs(s,INF);
}
}
// printf("%d\n",ans);
}
int low[N],dfn[N],scc[N],_clock,times;
stack<int>q;
void tarjan(int u){
low[u] = dfn[u] = ++times;
q.push(u);
for (int i = Head[u]; i; i = edge[i].next)
if (edge[i].w){
int v = edge[i].v;
if (!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if (!scc[v]) low[u] = min(low[u],dfn[v]);
}
if (low[u] == dfn[u]){
_clock++;
while(1){
int v = q.top(); q.pop();
scc[v] = _clock;
if (v == u) break;
}
}
}
int main(){
init();
Dinic();
for (int i = 1; i <= n; ++i)
if (!dfn[i]) tarjan(i);
for (int i = 1; i <= m; ++i)
if (edge[i*2].w) puts("0 0");
else{
int v = edge[i*2].v,u = edge[i*2+1].v;
printf("%d %d\n",scc[u] != scc[v],scc[u]==scc[s] && scc[v] == scc[t]);
}
return 0;
}