关键割边
??? 关键割边就是增加某条边的容量,使得网络的最大流增加。
??? 步骤:
??? 1. 求最大流,得到残余网络。
??? 2. 在残余图上从s点出发dfs,得到割边(a,b)。
??? 3. 从t点出发反向dfs,得到所有能到达t的点。
??? 4. 对于某条割边(a,b),若b能到达t,则该边为关键割边。(因为从s到t的路径上只有这一条割边,增加这条割边,肯定可以增加流量)。
?
例:POJ3024
??? 题意:找关键割边数量。
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int INF = 0x7fffffff;const int maxv = 505;const int maxe = 5005*2;int n,m;int col[maxv];bool vis[maxv];//struct Edge{ int v; int next; int flow;};Edge e[maxe];int head[maxv],edgeNum;int now[maxv],d[maxv],vh[maxv],pre[maxv],preh[maxv];void addEdge(int a,int b,int c){ e[edgeNum].v = b; e[edgeNum].flow = c; e[edgeNum].next = head[a]; head[a] = edgeNum++; e[edgeNum].v = a; e[edgeNum].flow = 0; e[edgeNum].next = head[b]; head[b] = edgeNum++;}void Init(){ edgeNum = 0; memset(head,-1,sizeof(head)); memset(d,0,sizeof(d));}int sap(int s,int t,int n) //源点,汇点,结点总数{ int i,x,y; int f,ans = 0; for(i = 0; i < n; i++) now[i] = head[i]; vh[0] = n; x = s; while(d[s] < n) { for(i = now[x]; i != -1; i = e[i].next) if(e[i].flow > 0 && d[y=e[i].v] + 1 == d[x]) break; if(i != -1) { now[x] = preh[y] = i; pre[y] = x; if((x=y) == t) { for(f = INF,i=t; i != s; i = pre[i]) if(e[preh[i]].flow < f) f = e[preh[i]].flow; ans += f; do { e[preh[x]].flow -= f; e[preh[x]^1].flow += f; x = pre[x]; }while(x!=s); } } else { if(!--vh[d[x]]) break; d[x] = n; for(i=now[x]=head[x]; i != -1; i = e[i].next) { if(e[i].flow > 0 && d[x] > d[e[i].v] + 1) { now[x] = i; d[x] = d[e[i].v] + 1; } } ++vh[d[x]]; if(x != s) x = pre[x]; } } return ans;}void minmGe(int x){ col[x] = 1; for(int i = head[x]; i != -1; i = e[i].next) { int to = e[i].v; if(e[i].flow > 0 && !col[to]) minmGe(to); }}//void dfs(int now){ vis[now] = true; for(int i = head[now]; i != -1; i = e[i].next) { if(i%2==0) continue; int to = e[i].v; if(e[i^1].flow>0&&!vis[to]) dfs(to); }}int main(){ int i,j; int from,to,c; Init(); memset(col,0,sizeof(col)); memset(vis,0,sizeof(vis)); scanf("%d %d",&n,&m); for(i = 0; i < m; i++) { scanf("%d %d %d",&from,&to,&c); addEdge(from,to,c); } sap(0,n-1,n); minmGe(0); int result = 0; dfs(n-1); for(i = 0; i < n; i++) { if(!col[i]) continue; for(j = head[i]; j != -1; j = e[j].next) { int to = e[j].v; if(j%2==0 && col[to]==0 && vis[to]) result++; } } printf("%d\n",result++); return 0;}?
?
?
?