题目大意:给出一个网络图,求出这其中的可行边和必须边。
思路:看了策爷的博客,知道了两个结论:
最小割的必须边和可行边:
求最大流,在残余网络中求出SCC。若:
1. 对于任意一条满流边,有changed[x] != changed[y],则这个边为可行边。
2. 对于任意一条满流边,有changed[x] == changed[S] && changed[y]== changed[T],则这个边为必须边。
之后就是结论题了。
CODE:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 120010 #define INF 0x3f3f3f3f using namespace std; int points,edges,S,T; int head[MAX],total = 1; int next[MAX << 1],aim[MAX << 1],from[MAX << 1],flow[MAX << 1]; int deep[MAX]; int dfn[MAX],changed[MAX],scc; inline void Add(int x,int y,int f) { next[++total] = head[x]; aim[total] = y; from[total] = x; flow[total] = f; head[x] = total; } inline void Insert(int x,int y,int f) { Add(x,y,f); Add(y,x,0); } inline bool BFS() { static queue<int> q; while(!q.empty()) q.pop(); memset(deep,0,sizeof(deep)); deep[S] = 1; q.push(S); while(!q.empty()) { int x = q.front(); q.pop(); for(int i = head[x]; i; i = next[i]) if(flow[i] && !deep[aim[i]]) { deep[aim[i]] = deep[x] + 1; q.push(aim[i]); if(aim[i] == T) return true; } } return false; } int Dinic(int x,int f) { if(x == T) return f; int temp = f; for(int i = head[x]; i; i = next[i]) if(flow[i] && deep[aim[i]] == deep[x] + 1 && temp) { int away = Dinic(aim[i],min(temp,flow[i])); if(!away) deep[aim[i]] = 0; flow[i] -= away; flow[i^1] += away; temp -= away; } return f - temp; } void Tarjan(int x) { static int low[MAX],total; static int stack[MAX],top; static bool in_stack[MAX]; dfn[x] = low[x] = ++total; stack[++top] = x; in_stack[x] = true; for(int i = head[x]; i; i = next[i]) if(flow[i]) { if(!dfn[aim[i]]) Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]); else if(in_stack[aim[i]]) low[x] = min(low[x],dfn[aim[i]]); } if(low[x] == dfn[x]) { ++scc; int temp; do { temp = stack[top--]; in_stack[temp] = false; changed[temp] = scc; }while(temp != x); } } int main() { cin >> points >> edges >> S >> T; for(int x,y,z,i = 1; i <= edges; ++i) { scanf("%d%d%d",&x,&y,&z); Insert(x,y,z); } while(BFS()) Dinic(S,INF); for(int i = 1; i <= points; ++i) if(!dfn[i]) Tarjan(i); for(int i = 2; i <= edges << 1; i += 2) { if(!flow[i]) { if(changed[from[i]] != changed[aim[i]]) printf("1 "); else printf("0 "); if(changed[S] == changed[from[i]] && changed[T] == changed[aim[i]]) puts("1"); else puts("0"); } else puts("0 0"); } return 0; }