您的位置:首页 > 其它

POJ 1815 求最小点割(拆点+枚举割边)

2012-06-14 19:46 253 查看
题目链接: http://poj.org/problem?id=1815

题目大意:

  给定n个人的关系,a,b互相有联系,b,c也互相有联系的话那么a,c也互相有联系(满足传递性),然后给定一个S,T,问最少需要删除多少个人使得S与T没有联系,如果有多种方案,输出字典序最小的。

分析:

  我直接百度的。

  这道题就是一个求源和汇点联通度的题,转换过来就是最大流最小割问题,把求点割转换到边割。

  http://hi.baidu.com/zfy0701/blog/item/a521f230b06dea9fa9018e0e.html

  我的代码还是根据枚举点,使得它不与其他点相连,求最大流看与初始流比较是否减少来判断该点是否属于最小割。更方便的做法还不会,另外fhq在discuss里说了一个很神奇的方法,看不懂。

代码:

poj1815

/*1815    Accepted    640K    782MS    C++    3965B    2012-06-14 17:35:11*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
#define maxn 410
#define maxm 20010
const int inf= 2100000000;

int n,m,S,T;
int ST, ED, NV;
int map[maxn][maxn];
int dis[maxn], pre[maxn], gap[maxn], cur[maxn];

int top, head[maxn];
struct Edge{
int v,w,next;
Edge(){}
Edge(int v,int w,int next): v(v), w(w), next(next){}
}edge[maxm];
void Addedge(int u,int v,int w){
edge[top]= Edge( v, w, head[u] );
head[u]= top++;
edge[top]= Edge( u, 0, head[v] );
head[v]= top++;
}

int sap(){
int maxflow= 0;
for(int i=0;i<NV;++i) dis[i]= gap[i]= 0, cur[i]= head[i];
int u= pre[ST]= ST;
int v, aug= inf;
gap[0]= NV;
while( dis[ST]<NV ){
for(int &i= cur[u]; i!=-1; i=edge[i].next){
v= edge[i].v;
if( edge[i].w && dis[u]==dis[v]+1 ) break;
}
if( -1 != cur[u] ){
up_min( aug, edge[ cur[u] ].w );
pre[v]= u;
u= v;
if( v==ED ){
maxflow+= aug;
for(u=pre[u];v!=ST;v=u,u=pre[u]){
edge[ cur[u] ].w-= aug;
edge[ cur[u]^1 ].w+= aug;
}
aug= inf;
}
}
else{
int mindis= NV;
for(int i=head[u]; i!=-1; i= edge[i].next){
int v= edge[i].v;
if( edge[i].w && up_min( mindis, dis[v] ) )
cur[u]= i;
}
if( --gap[ dis[u] ] == 0 ) break;
++gap[ dis[u]= mindis+1 ];
u= pre[u];
}
}
return maxflow;
}

void Init_graph(){
top= 0;
MM( head, -1 );
ST= 0, ED= n+n+1; NV= n+n+2; ///

Addedge( ST, S, inf );
Addedge( T+n, ED, inf );
for(int i=1;i<=n;++i){
if( i==S || i==T ) Addedge( i, i+n, inf );
else Addedge( i, i+n, 1 );
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if( map[i][j] && i!=j ) /// i!=j;
Addedge( i+n, j, inf );
}

bool mark[maxn];
void Rebuild_graph(int v){
top= 0;
MM( head, -1 );

/// ST= 0, ED= n+n+1, NV= n+n+2;
Addedge( ST, S, inf );
Addedge( T+n, ED, inf );
for(int i=1;i<=n;++i){
if( i==S || i==T ) Addedge( i, i+n, inf );
else if( i!=v && !mark[i] ) Addedge( i, i+n, 1 );
}
for(int i=1;i<=n;++i){
if( i==v || mark[i] ) continue;
for(int j=1;j<=n;++j)
if( map[i][j] && i!=j && j!=v && !mark[j] )
Addedge( i+n, j, inf );
}
}

int main()
{
//freopen("poj1815.in","r",stdin);
while( cin>>n>>S>>T ){
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
scanf("%d", &map[i][j]);

if( map[S][T]==1 ){ puts("NO ANSWER!"); continue; }

Init_graph();
int Flow= sap();
if( 0==Flow ){ puts("0"); continue; }

fill( mark, mark+1+n, 0 );
int cnt= 0;
for(int i=1;i<=n;++i){
if( i==S || i==T ) continue;
Rebuild_graph( i );
int tmp= sap();
if( up_min( Flow, tmp ) ){
++cnt;
mark[i]= 1;
}
}

/// output the answer;
printf("%d\n", cnt);
bool flag= 0;
for(int i=1;i<=n;++i){
if( mark[i] ){
if( flag ) printf(" ");
else flag= 1;
printf("%d", i);
}
}
puts("");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: