POJ 1966 最大流最小割...

时间:2023-02-02 20:12:22

最近写的代码都挺长的啊...

下面说一下最小割吧。

以下内容引自:这里

首先介绍一个概念:

点连通度:一个具有N个顶点的图G,去除K个顶点后,图成为非连通图,去除任意K-1个顶点后,图仍为连通图。责成图G为K连通图。

独立轨:A,B是图G中两个顶点,从A至B的无公共内顶点的路径叫做独立轨,其最大条数记为p(A,B);

POJ 1966 最大流最小割...

如上图中,将A=1,B=5;那么该图的最大独立轨数量为3

1-2-3-5,1-4-5,1-7-6-5;三条。

在这三条独立轨中,每条切除一个内点,该图的成为非连通图。如果p(G)=N-1,则该图为强连通图。

可见p(A,B)=K(G)。也就是图G独立轨的最大条数为图G的连通度。

由于每个内点只能用一次,可以套最大流模型...

将顶点v分割为v,v',e=(v,v')容量为1;做一次最大流就可以得出源点到汇点的最小割。

G无向图:

(1)顶点v分割为v,v'。e(v,v')容量为1;

(2)图中的无向边设为2条有向边,e(u,v)-->e(u',v)=INF,e(v',u)=INF;

(3)枚举源点u'和汇点v做最大流。

G有向图类似。

若结果流出的值为INF,则该图为强连通,去除N个顶点才能破坏连通性。

所有具有流量为1的弧(V,V')对应的V顶点组成一个割顶集

通过求连通度可以得到一个结论:G是K的连通图,k>=2,则任意K个顶点共圈。


边连通度:

解法类似,不过边连通,点可以走很多次,边只能走一次。

(1)对于无向边e(u,v) 在(u,v),(v,u)之间添加容量为1的流边。

(2)枚举源点汇点,求最大流,即为边连通度。

求出的残余网络中,流量为1的弧e`=(u,v),e`就是割边。





#include<iostream>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define MN 111
#define INF 0x3FFFFFFF
#define CC(a) memset( a,0,sizeof(a) )
#define FF(i,N) for( int i=0;i<N;i++ )
template<class T>void inline checkmin( T &a,T b ){ if( a>b||a==-1 ) a=b; }
template<class T>void inline checkmax( T &a,T b ){ if( a<b ) a=b; }
using namespace std;

int maze[MN][MN],map[MN][MN],dis[MN],cur[MN],gap[MN],pre[MN];
int N,M,s,t;

void setG()
{
 	 CC(map);
 	 FF( i,N )
 	 	 map[i][i+N]=1;
 	 int u,v;
 	 FF( i,M ){
 	 	 scanf( " (%d,%d)",&u,&v );
 	 	 map[u+N][v]=map[v+N][u]=INF;
	 }
}

void initG()
{
 	 FF(i,N<<1)FF(j,N<<1)
 	 maze[i][j]=map[i][j];
}

int sap( int s,int t )
{
 	CC(cur),CC(gap),CC(dis);
 	int u=pre[s]=s,maxflow=0,aug=-1;
 	gap[0]=2*N;
 	while( dis[s]<2*N ){
loop:
	 	   for( int v=cur[u];v<2*N;v++ )
	 	   if( maze[u][v]&&dis[u]==dis[v]+1 )
		   {
		   	   pre[v]=u;
		   	   cur[u]=v;
		   	   checkmin( aug,maze[u][v] );
		   	   u=v;
		   	   if( v==t )
		   	   {
			   	   maxflow+=aug;
			   	   for( u=pre[u];v!=s;v=u,u=pre[u] )
			   	   		maze[u][v]-=aug,maze[v][u]+=aug;
			   	   aug=-1;
   	   		   }
			   goto loop;		
		   }
		   int mind=2*N;
		   for( int v=0;v<2*N;v++ )
		   if( maze[u][v]&&mind>dis[v] )
		   {
		   	   mind=dis[v];
		   	   cur[u]=v;
   		   }
   		   if( --gap[dis[u]]==0 ) break;
   		   gap[dis[u]=mind+1]++;
   		   u=pre[u];
  	}
  	return maxflow;
}

int main()
{
 	while( scanf("%d%d",&N,&M)!=EOF )
 	{
	 	   int ans=INF;
	 	   setG();
	 	   for( int i=0;i<N;i++ )
	 	   for( int j=i+1;j<N;j++ )
		   {
		   	   initG();
		   	   checkmin( ans,sap(i+N,j) );
		   	   //printf( "ans:%d\n",ans );
   		   }
   		   if( ans==INF )
   		   	   printf( "%d\n",N );
   		   else
   		   	   printf( "%d\n",ans );
  	}
 	return 0;
}