您的位置:首页 > 其它

POJ 1815 最小割

2013-01-06 22:14 393 查看
题意:

n个人的两两关系矩阵,如果a认识b,则b认识a,且认识有传递性。给出一个s和一个t,问想让s不认识t,最少需要去掉多少人。
如果有解,输出字典序最小的解。

题解:

请特别注意0与NO ANSWER!的区别!

具体做法是:拆点限流,先求一次最小割为ans,然后从小到大枚举删除的点,重新建图再做最小割,如果当前结果比ans小,则更新ans,并把这个节点打上vis标记。

ps:已经打上vis标记的点不再参与之后重建图时

View Code

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>

#define N 500
#define M 40000
#define INF 1e9

using namespace std;

int head
,to[M],next[M],len[M];
int q[M*4],layer
;
bool map

,vis
;
int n,S,T,tt,ss,cnt;

inline void add(int u,int v,int w)
{
to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
//printf("%d   %d   %d\n",u,v,w);
}

inline bool read()
{
memset(head,-1,sizeof head); cnt=0;
memset(vis,0,sizeof vis);
memset(map,0,sizeof map);
S=0; T=n+n+1;

for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
if(map[ss][tt]) return false;

add(S,ss,INF); add(tt+n,T,INF);
for(int i=1;i<=n;i++)
{
if(i==ss||i==tt) add(i,i+n,INF);
else add(i,i+n,1);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(map[i][j]&&i!=j) add(i+n,j,INF);
return true;
}

inline void rebuild(int u)
{
memset(head,-1,sizeof head); cnt=0;
add(S,ss,INF); add(tt+n,T,INF);
for(int i=1;i<=n;i++)
{
if(i==ss||i==tt) add(i,i+n,INF);
else if(i!=u&&!vis[i]) add(i,i+n,1);
}
for(int i=1;i<=n;i++)
{
if(i==u||vis[i]) continue;
for(int j=1;j<=n;j++)
if(map[i][j]&&j!=u&&i!=j&&!vis[j])
add(i+n,j,INF);
}
}

inline bool bfs()
{
memset(layer,-1,sizeof layer);
int h=1,t=2,sta;
q[1]=S; layer[S]=0;
while(h<t)
{
sta=q[h++];
for(int i=head[sta];~i;i=next[i])
if(len[i]&&layer[to[i]]<0)
{
layer[to[i]]=layer[sta]+1;
q[t++]=to[i];
}
}
return layer[T]!=-1;
}

inline int find(int u,int cur_flow)
{
if(u==T) return cur_flow;
int res=0,tmp;
for(int i=head[u];~i&&res<cur_flow;i=next[i])
if(len[i]&&layer[to[i]]==layer[u]+1)
{
tmp=find(to[i],min(cur_flow-res,len[i]));
len[i]-=tmp; len[i^1]+=tmp; res+=tmp;
}
if(!res) layer[u]=-1;
return res;
}

inline void go()
{
int ans=0,num=0;
while(bfs()) ans+=find(S,INF);
if(!ans)
{
puts("0");
return;
}
for(int i=1,res;i<=n;i++)
if(i!=ss&&i!=tt)
{
res=0;
rebuild(i);
while(bfs()) res+=find(S,INF);
if(ans>res) vis[i]=true,num++,ans=res;
}
printf("%d\n",num);
for(int i=1,sg=0;i<=n;i++)
if(vis[i])
{
if(!sg) sg=true,printf("%d",i);
else printf(" %d",i);
}
puts("");
}

int main()
{
while(scanf("%d%d%d",&n,&ss,&tt)!=EOF)
{
if(!read()) puts("NO ANSWER!");
else go();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: