题意: 给出有n 个节点的网络,和m条单向边,知道了每条边的容量,问哪些边满足增加该边的容量后,能使得从起点到终点的总流量增加(只能修改一条边!)。
注意一点,在一条流路中只能修改一条,好像s->1->2->t,假设每条边的容量都是2,那么最大流的流路只有一条,但是这条流路中,
要想增大一条边的容量而使整个网络的最大流增加是不行的,一定要把所有边容量都增大,这与题意不符,所以这个case输出是0,表示1条都没有
注意一点,在一条流路中只能修改一条,好像s->1->2->t,假设每条边的容量都是2,那么最大流的流路只有一条,但是这条流路中,
要想增大一条边的容量而使整个网络的最大流增加是不行的,一定要把所有边容量都增大,这与题意不符,所以这个case输出是0,表示1条都没有
那么题目就转化成了在求最大流后的残流网络中求这样的一个满流边集x-y(边的容量为0),使得如果在残余网络中存在路径[S,X]和[Y,T],该边集的边的条数即为所求。找满流边集很容量,关键是判断这个满流边集中的边两端点i,j,使i能由S到达且j能达到T。那么可以对S进行一次DFS(能够联通的点标记在v1中),然后将图反向后再从T DFS一遍(能够联通的点标记在v2中)。那么对于满流集合中任意一条有向边i->j,如果v1[i]和v2[j]均标记过,则满足上述性质,为题中所求的边中的一条。
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=600 ;
const int M=100000;
const int inf=1<<30 ;
struct node
{
int u,v,c,next;
}edge[M];
int head[N],cur[N],dis[N],gap[N],pre[N];
int top ,g[N][N],v1[N],v2[N];
int n,m;
void add(int u ,int v,int c)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].next=head[v];
head[v]=top++;
}
void sap(int s,int t ,int nv)
{
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
int u,v,minflow=inf,flow=0;
for(int i = 0 ; i <nv ; i++) cur[i]=head[i] ;
u=pre[s]=s;
gap[s]=nv;
while(dis[s] < nv )
{
loop :
for(int &j=cur[u] ; j!=-1 ; j=edge[j].next)
{
v=edge[j].v ;
if(edge[j].c > 0 && dis[u] == dis[v] +1 )
{
minflow = min(minflow ,edge[j].c) ;
pre[v]=u;
u=v ;
if(v==t)
{
for( u =pre[v] ; v!=s ;v=u,u=pre[u])
{
edge[cur[u]].c -= minflow ;
edge[cur[u]^1].c += minflow ;
}
flow += minflow ;
minflow = inf ;
}
goto loop ;
}
}
int mindis=nv ;
for(int i = head[u] ; i!=-1 ; i=edge[i].next)
{
v=edge[i].v ;
if(edge[i].c > 0 && dis[v] < mindis)
{
mindis = dis[v] ;
cur[u]=i ;
}
}
if(--gap[dis[u]]==0) break ;
gap[ dis[u] = mindis +1 ]++ ;
u=pre[u] ;
}
}
void dfs1(int u)
{
v1[u]=1;
for(int i = 0 ; i < n; i++)
{
if(!v1[i] && g[u][i])
dfs1(i);
}
}
void dfs2(int u)
{
v2[u]=1;
for(int i = 0 ; i < n; i++)
{
if(!v2[i] && g[u][i])
dfs2(i);
}
}
int main()
{
int a,b,c;
while(~scanf("%d%d",&n,&m))
{
top=0;
memset(head,-1,sizeof(head));
memset(v1,0,sizeof(v1));
memset(v2,0,sizeof(v2));
int s=0,t=n-1 ;
for(int i = 1 ; i <= m ; i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c) ;
}
sap(s,t,n);
memset(g,0,sizeof(g)) ;
for(int i = 0 ; i < top ; i=i+2)
{
int u=edge[i].u;
int v=edge[i].v;
if(edge[i].c != 0)
g[u][v]=1;
}
dfs1(s) ;
memset(g,0,sizeof(g)) ;
for(int i = 0 ; i < top ; i=i+2)
{
int u=edge[i].u;
int v=edge[i].v;
if(edge[i].c != 0)
g[v][u]=1;
}
dfs2(t) ;
int ans = 0;
for(int i = 0 ; i < top ; i=i+2)
{
if(v1[edge[i].u] && !edge[i].c && v2[edge[i].v])
ans++;
}
printf("%d\n",ans);
}
return 0;
}