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

这题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;
}


你可能感兴趣的:(POJ 1815 最大流最小割枚举找割点)