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;
}
题意:
在联系网中,去掉最少的联系点使得从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;
}
相关文章推荐
- Friendship (poj 1815 最小点割集+枚举)
- poj 1815(最小割 + 枚举)
- 【POJ】1815 Friendship 枚举+最大流。。
- POJ 1815 最小割 拆点 枚举
- POJ 1815 求最小点割(拆点+枚举割边)
- [最小点割集]poj 1815 #贪心枚举
- poj 1815(最小割+枚举)
- POJ 1815 Friendship(最大流最小割の字典序割点集)
- poj 1815 Friendship (最小割+拆点+枚举)
- poj 1815 Friendship (最小割+拆点+枚举)
- Poj 1815 Friendship 枚举+求最小割
- 【最小割+枚举】POJ-1815 Friendship
- poj 1815 Friendship 【最小割点集】【枚举删点 + 求解最小字典序】
- poj 1815 最小点割转化为最小边割+枚举 (邻接矩阵+递归dinic)
- POJ 1815 - Friendship 求最小割点..要求字典序...枚举+最小割
- poj--1815--Friendship(最小割点集)(枚举求最小字典序)
- poj 2594 Treasure Exploration(最小路径覆盖->最大匹配)
- poj 2309 按位与 &(以x为根的满二叉搜索树的最小节点编号、最大节点编号)
- POJ 2112--Optimal Milking【二分找最大距离的最小值 && 最大流dinic】
- POJ 2455--Secret Milking Machine【二分枚举 && 最大流 && 经典】