题意:给出一个流网络,问有仅将一条边的容量增大可以使得最大流增大的边有多少条。
首先,肯定将是满流的边的容量增大才可能使得最大流增大。但是这些满流的边不一定能是最小割,即使它出现在最小割中,把它的容量增大也不一定能使最大流增大。那么考虑一下求完最大流后不能增广的原因,或者说,怎么样才能在残量网络中增广呢?从S出发,dfs出所有满流的正向边,给dfs经过的点标上f1。再从T出发,逆向dfs出所有满流的边,给dfs经过的点标上f2。那么如果有一条边是这样的:满流且有f1标记和f2标记,那么增加它的容量,残量网络就又可以增广了,最大流会增加,因此这样的边就是我们需要寻找的边。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define INF 1<<30 6 #define maxn 510 7 #define maxm 100000 8 using namespace std; 9 10 int u[maxm],v[maxm],next[maxm],w[maxm]; 11 int first[maxn],d[maxn],work[maxn],q[maxn]; 12 int e,S,T; 13 bool f1[maxn],f2[maxn]; 14 int n,m; 15 void init(){ 16 memset(first,-1,sizeof(first)); 17 e = 0; 18 } 19 20 void add_edge(int a,int b,int c){ 21 u[e] = a;v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++; 22 u[e] = b;v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++; 23 } 24 25 int bfs(){ 26 int rear = 0; 27 memset(d,-1,sizeof(d)); 28 d[S] = 0;q[rear++] = S; 29 for(int i = 0;i < rear;i++){ 30 for(int j = first[q[i]];j != -1;j = next[j]) 31 if(w[j] && d[v[j]] == -1){ 32 d[v[j]] = d[q[i]] + 1; 33 q[rear++] = v[j]; 34 if(v[j] == T) return 1; 35 } 36 } 37 return 0; 38 } 39 40 int dfs(int cur,int a){ 41 if(cur == T) return a; 42 for(int &i = work[cur];i != -1;i = next[i]) 43 if(w[i] && d[v[i]] == d[cur] + 1) 44 if(int t = dfs(v[i],min(a,w[i]))){ 45 w[i] -= t;w[i^1] += t; 46 return t; 47 } 48 return 0; 49 } 50 51 int dinic(){ 52 int ans = 0; 53 while(bfs()){ 54 memcpy(work,first,sizeof(first)); 55 while(int t = dfs(S,INF)) ans += t; 56 } 57 return ans; 58 } 59 60 void dfs1(int u){ 61 f1[u] = 1; 62 for(int i = first[u];i != -1;i = next[i]){ 63 if(!f1[v[i]] && w[i]) dfs1(v[i]); 64 } 65 } 66 67 void dfs2(int u){ 68 f2[u] = 1; 69 for(int i = first[u];i != -1;i = next[i]){ 70 if(!f2[v[i]] && w[i^1]) dfs2(v[i]); 71 } 72 } 73 74 int solve(){ 75 memset(f1,0,sizeof(f1)); 76 memset(f2,0,sizeof(f2)); 77 dfs1(S); 78 dfs2(T); 79 int ret = 0; 80 for(int i = 0;i < e;i += 2){ 81 if(f1[u[i]] && f2[v[i]] && !w[i]) 82 ret++; 83 } 84 return ret; 85 } 86 87 int main() 88 { 89 init(); 90 int n,m; 91 scanf("%d%d",&n,&m); 92 S = 0,T = n-1; 93 for(int i = 0;i < m;i++){ 94 int a,b,c; 95 scanf("%d%d%d",&a,&b,&c); 96 add_edge(a,b,c); 97 } 98 dinic(); 99 printf("%d ",solve()); 100 return 0; 101 }