您的位置:首页 > 其它

POJ 1815 最大流最小割枚举找割点

2012-04-19 13:22 417 查看
这题WA得我SB一样.......竟然是声明了一个函数没有调用.....

题意:

在联系网中,去掉最少的联系点使得从S和T无法联系。

赤裸裸的求最小割点集的问题;

建图:

网上都有,就不说了。

怎样找割点呢?在这里变成了割边。

上一题POJ2125用的是DFS,找到集合S,那么分跨S与T集合的边就是割边了。

这么做,对于二分图还是很方便的。这里却行不通了。

前面讲过独立轨的概念,图G独立轨最大条数p(S,T),就是图的点割集的个数。

在每条独立轨的内顶点取一个点,组成的就是点割集了。

这题要求的是字典序最小的点割集,当然。。。 不能那么做了....

先用2B一点的做法,枚举每个割点,如果去掉该点,影响了点割集的数量,那么该点为割点。割点集--。

再继续做,如果没有影响,则该点不在独立轨上或者在前点的同一条独立轨上。

这样,找到所有的独立轨上的字典序最小的割点就好了。

代码十分的坑爹... 1900ms++。看来要换模版了....

#include<iostream>
#include<cstdio>
#define CC(a) memset( a,0,sizeof(a) )
#define MN 444
#define INF 0x7FFFFFFF
template<class T>void inline checkmin( T &a,T b ){ if( a>b||a==-1 ) a=b; }
using namespace std;

int cap[MN][MN],flow[MN][MN],gap[MN],cur[MN],dis[MN],pre[MN];
int N,s,t;

void setG()
{
CC(cap),CC(flow);
for( int i=1;i<=N;i++ )
cap[i][i+N]=1;
cap[t+N][t]=cap[s+N][s]=INF;
int v;
for( int i=1;i<=N;i++ )
for( int j=1;j<=N;j++ )
{
scanf("%d",&v);
if( i==j ) continue;
if(v)cap[i+N][j]=INF;
}
}

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

int main()
{
int cnt,rec[MN];
while( scanf("%d%d%d",&N,&s,&t)!=EOF )
{
setG();
int maxflow=sap();
if( maxflow==INF )
{
printf( "NO ANSWER!\n" );
continue;
}
printf( "%d\n",maxflow );
cnt=0;
//printf( "s:%d t:%d\n",s,t );
for( int i=1;i<=N;i++ )
{
if( i==s || i==t ) continue;
cap[i][i+N]=0;
int cur=sap();
//printf( "cur:%d\n",cur );
if( cur<maxflow )
{
maxflow--;
rec[cnt++]=i;
cap[i][i+N]--;
}
cap[i][i+N]++;
if(maxflow==0) break;
}
for( int i=0;i<cnt;i++ )
if(i)printf(" %d",rec[i]);
else printf("%d",rec[i]);
printf( "\n" );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sap