poj 3204 最小割(关键割边)

本文讨论了最大流问题及其在残流网络中的应用,通过实例解析如何找到能够增加网络最大流量的边集,并提供了求解算法的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意: 给出有n 个节点的网络,和m条单向边,知道了每条边的容量,问哪些边满足增加该边的容量后,能使得从起点到终点的总流量增加(只能修改一条边!)。
注意一点,在一条流路中只能修改一条,好像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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值