题目:POJ-1815
题意:在一个给定的无向图中至少应该去掉几个顶点才干使得s和t不联通。
题解:
假设s和t直接相连输出no answer。
把每一个点拆成两个点v和v'',这两个点之间连一条权值为1的边(残余容量)
v和v''各自是一个流进的点。一个流出的点。
依据求最小割的性质。权值小的边是可能被选择的(断开的)。
加入源点st=0和汇点en=2*n+1,源点与s连权值为inf的边。t''与汇点连权值为inf的边。
s与s'',t与t''连权值为inf的边,这样保证自己和自己是不会失去联系的。
假设i和j有边相连。则i''和j连权值为inf的边。j''与i连权值为inf的边。
这样建图后跑最大流,求得的流量即为点的个数。
然后编号从小到大枚举每一个点。尝试去掉这个点(即仅仅进不出)。又一次建图再跑最大流。
看最大流是否会减小。假设减小了,就是要去掉的点,输出就好了,然后更新当前的最大流。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 100005
#define INF 0x7fffffff
using namespace std;
int n,s,t,S,T,c;
int head[N],cur[N],deep[N],mp[205][205];
bool vis[N];
struct ljh
{
int next,to,w;
}e[N*2];
inline void add(int x,int y,int z)
{
e[c].next=head[x];
e[c].w=z;
e[c].to=y;
head[x]=c++;
e[c].next=head[y];
e[c].w=0;
e[c].to=x;
head[y]=c++;
}
void build()
{
memset(head,-1,sizeof(head));
c=0;
add(S,s,INF);
add(t+n,T,INF);
for(int i=1;i<=n;i++)
{
if(vis[i]==0&&i!=s&&i!=t)add(i,i+n,1);
for(int j=1;j<=n;j++)
{
if(mp[i][j]==1)
add(i+n,j,INF);
}
}
add(s,s+n,INF);
add(t,t+n,INF);
}
bool bfs(int S,int T)
{
memset(deep,0,sizeof(deep));
deep[S]=1;
queue<int>q;
q.push(S);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=e[i].next)
{
int nex=e[i].to;
if(deep[nex]==0&&e[i].w>0)
{
deep[nex]=deep[x]+1;
q.push(nex);
}
}
}
return deep[T];
}
int dfs(int x,int T,int maxflow)
{
if(x==T)return maxflow;
int ans=0;
for(int i=cur[x];i!=-1;i=e[i].next)
{
int nex=e[i].to;
if(deep[nex]!=deep[x]+1||ans>=maxflow||e[i].w<=0)continue;
cur[x]=i;
int k=dfs(nex,t,min(e[i].w,maxflow-ans));
e[i].w-=k;
e[i^1].w+=k;
ans+=k;
}
if(ans==0)deep[x]=-2;
return ans;
}
int Dinic(int S,int T)
{
int ans=0;
while(bfs(S,T))
{
memcpy(cur,head,sizeof(head));
ans+=dfs(S,T,INF);
}
return ans;
}
int main()
{
while(~scanf("%d%d%d",&n,&s,&t))
{
S=0;
T=2*n+1;
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&mp[i][j]);
if(mp[s][t]==1){ printf("NO ANSWER!\n");continue;}
build();
int ans=Dinic(S,T);
printf("%d\n",ans);
if(ans==0)continue;
int tmp=ans;
for(int i=1;i<=n;i++)
{
if(i==s||i==t)continue;
vis[i]=1;
build();
int sum=Dinic(S,T);
// cout<<sum<<endl;
if(sum<tmp)
{
tmp=sum;
printf("%d ",i);
}
else vis[i]=0;
if(tmp==0){break;}
}
printf("\n");
}
}
/*
7 1 7
1 1 0 1 0 0 0
1 1 1 0 0 0 0
0 1 1 1 0 0 1
1 0 1 1 1 1 0
0 0 0 1 1 0 1
0 0 0 1 0 1 1
0 0 1 0 1 1 1
*/