POJ 3084 最大流最小割求割边

这种题目做过蛮多道了,主要是再练习一下我的网络流链表写法。

这题坑爹的理解错题意了,弄了很久。

题意:

有M个房间,现在要保护N号房间,房间编号为[0,M-1]。起初所有的房间的门都是打开的,房间内有关门的控制面板,也就是说,如果该房间能控制几个相应的门,则从该房间可以通过这些门去往其他房间。如果控制面板在其他房间里,这门就不能在这房间里打开。

现在要求的是关上最少的门使得要保护的房间不被入侵。

思路:

首先简化模型,不考虑,控制关系,也就是说,门都是双向的。那么门可以从两边打开,则在两房间连上容量为1的边,代表关上这门的容量。

这就是十分赤裸裸的割边模型了。

现在,我们加入另外一个条件,控制关系,如果U控制了V的房门,那么不论怎样,这门一定不是割边,因为不能关上,一旦流流过,是不能控制的。

所以U向V有边,容量为INF。而V向U有容量为1的边,代表从开门到关门状态的花销。

这么构图就好了。最大流=最小割...

wait.... 十分2逼的事情就是我去求割边了....

求增广轨的数量... 难怪求其来十分的不对劲....

#include<iostream>
#include<cstdlib>
#include<cstdio>
#define NV 55
#define NE 999
#define INF 0x7FFFFFFF
#define eps 1e-8
#define CC(a) memset(a,0,sizeof(a))
#define FF(i,N) for( int i=0;i<N;i++ )
template<class T> inline void checkmin( T &a,T b ){ if( a>b||a==-1 ) a=b; }
using namespace std;

int M,N,s,t,alloc;
struct edge{
   int u,v,c,f,next;
}E[NE];
int gap[NV],dis[NV],cur[NV],pre[NV],flag[NV],head[NV];

void addEdge( int u,int v,int c,int cc=0 )
{
 	 E[alloc].u=u; E[alloc].v=v;
 	 E[alloc].c=c; E[alloc].next=head[u];
 	 head[u]=alloc++;
 	 E[alloc].u=v; E[alloc].v=u;
 	 E[alloc].c=cc;E[alloc].next=head[v];
 	 head[v]=alloc++;
}

void setG()
{
 	 CC(E);alloc=0;
 	 memset( head,-1,sizeof(head) );
 	 char str[11];int n,v;
 	 scanf( "%d%d",&M,&N );
 	 s=0;t=M+1;
 	 addEdge( N+1,t,INF );
 	 FF( i,M )
 	 {
 	  	 /**printf( "1\n" );/**/
 		 scanf( "%s %d",&str,&n );
 		 if( str[0]=='I' )
 		 	 addEdge(s,i+1,INF);
 		 while( n-- )
		 {
		  		scanf( "%d",&v );
		  		addEdge( i+1,v+1,INF,1 );
		  		//addEdge( v+1,i+1,1,1 );
  		 }
	 }/***
	 FF(i,alloc)
	 printf( "u:%d v:%d c:%d next:%d\n",E[i].u,E[i].v,E[i].c,E[i].next );/***/
}

int sap()
{
 	CC(gap),CC(dis);
 	for( int i=0;i<=t;i++ )
 		 cur[i]=head[i];
 	int u=pre[s]=s,maxflow=0,aug=-1;
 	gap[0]=t+1;
 	while( dis[s]<=t ){
loop:
	 	   for( int &i=cur[u];i!=-1;i=E[i].next )
	 	   {
		   		int v=E[i].v;
		   		if( E[i].c-E[i].f&&dis[u]==dis[v]+1 )
				{
				 	pre[v]=u;
				 	checkmin(aug,E[i].c-E[i].f);
				 	u=v;
				 	if( v==t )
				 	{
					 	maxflow+=aug;
					 	for( u=pre[u];v!=s;v=u,u=pre[u] )
					 		 E[cur[u]].f+=aug,E[cur[u]^1].f-=aug;
					 	aug=-1;
		 		 	}
		 		 	goto loop;
		 		}
		   }
		   int mind=t;
		   for( int i=head[u];i!=-1;i=E[i].next )
		   {
		   		int v=E[i].v;
		   		if( E[i].c-E[i].f&&mind>dis[v] )
	   				cur[u]=i,mind=dis[v];
   		   }
   		   if( --gap[dis[u]]==0 ) break;
   		   gap[dis[u]=mind+1]++;
   		   u=pre[u];
  	}
  	return maxflow;
}

void dfss( int cur )
{
 	 flag[cur]=1;
 	 for( int i=head[cur];i!=-1;i=E[i].next )
 	 if( !flag[E[i].v]&&E[i].c-E[i].f )
 	 	 dfss(E[i].v);
}
void dfst( int cur )
{
 	 flag[cur]=2;
 	 for( int i=head[cur];i!=-1;i=E[i].next )
 	 if( !flag[E[i].v]&&E[i].c-E[i].f )
 	 	 dfst(E[i].v);
}

int main()
{
 	int T;
 	scanf( "%d",&T );
 	while( T-- )
 	{
	 	   setG();
	 	   int maxflow=sap();
	 	   /**printf("maxflow:%d\n",maxflow);/**/
	 	   if( maxflow==INF ){
		   	   printf( "PANIC ROOM BREACH\n" );
		   	   continue;
		   }
	 	   CC(flag);
	 	   dfss(s),dfst(t);/***
	 	   for( int i=0;i<=t;i++ )
	 	   		printf( "%d ",flag[i] );/***/
	 	   int sum=0;
	 	   for( int i=0;i<alloc;i++ )
	 	   if( flag[E[i].u]==1&&flag[E[i].v]==2&&E[i].c==E[i].f )
	 	   	   sum++;
  	   	   printf( "%d\n",sum );
  	}
  	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值