POJ 3204 Ikki's Story I - Road Reconstruction【关键割边】
题意: 给出有n 个节点的网络,和m条单向边,知道了每条边的容量,问哪些边满足增加该边的容量后,能使得从起点到终点的总流量增加(只能修改一条边!)。
分析:如果某条边是该关键边,首先满足该边一定能满流,其次要有从 s 到 t 经过该边的可行路径。
先求最大流,找出割边,在正向网络上从 s 开始深搜,将遍历到点用v1[]标记,在反向网络上从 t 深搜,将遍历到的点用v2[]标记,
如果某条边满足 e[i].cap=e[i].flow且v1[e[i].from]=1,e[e[i].to]=1,那么该边即为要求的关键边。
#include<stdio.h> #include<string.h> #define INF 0x1f1f1f1f #define maxn 500 #define min(a,b)(a)<(b)?(a):(b) #define max(a,b)(a)>(b)?(a):(b) #define clr(x)memset(x,0,sizeof(x)) struct node { int from,to,next,c,f; }e[100000]; int tot; int head[maxn]; void add(int s,int u,int wi) { e[tot].from=s; e[tot].c=wi; e[tot].f=0; e[tot].to=u; e[tot].next=head[s]; head[s]=tot++; e[tot].from=u; e[tot].c=0; e[tot].f=0; e[tot].to=s; e[tot].next=head[u]; head[u]=tot++; } void EK(int s,int t,int n) { int a[maxn]; int p[maxn]; int q[maxn]; int i,u,k,front,rear; p[s]=-1; while(1) { clr(a); a[s]=INF; front=rear=0; q[rear++]=s; while(front<rear) { u=q[front++]; for(i=head[u];i!=-1;i=e[i].next) { k=e[i].to; if(!a[k]&&e[i].f<e[i].c) { p[k]=i; q[rear++]=k; a[k]=min(a[u],e[i].c-e[i].f); } } } if(a[t]==0) break; for(u=p[t];u!=-1;u=p[e[u].from]) { e[u].f+=a[t]; e[u^1].f-=a[t]; } } } int v1[maxn],v2[maxn]; int g[maxn][maxn]; int n; void dfs1(int r) { int i; v1[r]=1; for(i=0;i<n;i++) if(!v1[i]&&g[r][i]) dfs1(i); } void dfs2(int r) { int i; v2[r]=1; for(i=0;i<n;i++) if(!v2[i]&&g[r][i]) dfs2(i); } int main() { int i,s,t,m,a,b,cc,res; while(scanf("%d%d",&n,&m)!=EOF) { tot=0; memset(head,-1,sizeof(head)); while(m--) { scanf("%d%d%d",&a,&b,&cc); add(a,b,cc); } s=0; t=n-1; clr(v1); clr(v2); EK(s,t,n); clr(g); for(i=0;i<tot;i+=2) if(e[i].c!=e[i].f) g[e[i].from][e[i].to]=1; dfs1(s); clr(g); for(i=0;i<tot;i+=2) if(e[i].c!=e[i].f) g[e[i].to][e[i].from]=1; dfs2(t); res=0; for(i=0;i<tot;i+=2) { if(v1[e[i].from]&&v2[e[i].to]&&e[i].f==e[i].c) res++; } printf("%d\n",res); } return 0; }