您的位置:首页 > 其它

POJ 1966 Cable TV Network(证明有误)

2010-12-21 19:21 246 查看
求图的点连通度

点连通度的定义:一个具有N个点的图G中,在去掉任意k-1个顶点后(1<=k<=N),所得的子图仍然连通,去掉K个顶点后不连通,则称G是K连通图,K称作图G的连通度,记作K(G)。即去掉最少个数的点后,子图不连通或者成为平凡图

做法:拆点(无向无向边拆成两条有向边),指定一个源点,枚举汇点(如果汇点与源点不连通,则图不连通),求使源汇不连通最少要移除的点数,并取最小值,如果最小值比n大,则最小值为n

详情见:http://hi.baidu.com/lerroy312/blog/item/d7ea97ee7b1f3cddd439c927.html

对于为什么只要枚举汇点:

假设点连通度为k,那么如果你枚举源汇,我们构图的时候是拆点的,所有最小割中最小的一定是k,对应k个点,割边为这k个点拆点后对应的边,那么,这个最小割把所有点点分成了两部分,S和T集合,S和T集合中的点都是不连通的,而S集合中的点都是连通的,T集合中的点也都是连通的,对于任意一个点i属于S,任意一个点j属于T,要使得他们不连通,在图中删除的点都为k,不可能更小了,否则最小割值比k小,而如果他们同时属于S集合或者T集合,使得他们不连通,要删除的点大于k,因为他们现在还连通,于是,如果我们指定一个源点,枚举汇点,如果这个源点与汇点同时在刚才那个最小割的S或T集合中,要使他们不连通,删除的点必然大于k,如果他们一个属于S,一个属于T,那么使他们不连通,要删除的点就是k个,所以,只要枚举汇点就行了

代码:

#include<iostream>
#include<cstdio>
#include<memory.h>
#include<algorithm>
using namespace std;
const int inf=1<<29;
const int MAX=105;
int c[MAX][MAX],f[MAX][MAX],pre[MAX],q[MAX],rc[MAX];
int n,m,s,t,max_flow;
bool bfs()
{
int i,j,tail=1,head=0;
memset(rc,0,sizeof(rc));
q[tail]=s;
pre[s]=-1;
rc[s]=inf;
while(head<tail)
{
i=q[++head];
for(j=1;j<=n*2;j++)
{
if(c[i][j]>f[i][j]&&!rc[j])
{
rc[j]=min(rc[i],c[i][j]-f[i][j]);
pre[j]=i;
q[++tail]=j;
if(j==t)
return true;
}
}
}
return false;
}
int EK()
{
int i;
max_flow=0;
while(bfs())
{
for(i=t;i!=s;i=pre[i])
{
f[pre[i]][i]+=rc[t];//加减别搞反了
f[i][pre[i]]-=rc[t];
}
max_flow+=rc[t];
}
return max_flow;
}
int main()
{
int i,j,a,b,ans,flow;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0)
{
puts("0");
continue;
}
memset(c,0,sizeof(c));
for(i=1;i<=n;i++)
c[i][i+n]=1;
for(i=1;i<=m;i++)
{
scanf(" (%d,%d)",&a,&b);
c[a+1+n][b+1]=inf;
c[b+1+n][a+1]=inf;
}
ans=inf;
s=n+1;
for(i=2;i<=n;i++)
{
memset(f,0,sizeof(f));
t=i;
flow=EK();
cout<<"flow="<<flow<<endl;
if(flow<ans)
ans=flow;
}
if(ans==inf)//构图局限性,最多只能删除n-1个点,而有些图必须删除n个点
ans=n;
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: