点双连通分量
在一个连通图中(无向图)任选两点,如果他们之间至少存在两条“点不重复”的路径,称这个图为点双连通。一个图中的点双连通极大子图称为“点双连通分量”(block,2-connected component,BCC)。点双连通分量是个“可靠”的图,去掉任意一个点,其他点任然是连通的。也就是说,点双连通分量中没有割点。
这是一种特殊的点双连通分量,因为他不满足上述定义。
求解点双连通分量和求割点密切相关。不同点双连通分量最多只有一个公共点,这个点就是割点;任意一个割点都是至少两个点双连通分量的公共点。
从任意一个点开始DFS,将图中的边入栈(因为一条边属于一个BCC,而点如割点,属于多个BCC),每次确认一个点是割点,就相当于找到了个BCC。
例题:hdu 3394
参考代码
//-------------------------------
//hdu 3394
//-------------------------------
#include<iostream>
#include<stack>
#include<vector>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int N=1e4+10;
int n,m;
vector<int>g[N];
int low[N],dfn[N],cnt;
int bcc[N];
int bcccnt;
struct edge{
int u,v;
};
int Min(int a,int b){
return a<b?a:b;
}
stack<edge>st;
int ansa,ansb;
int tarjan(int u,int fr){
int len=g[u].size();
int lowu=low[u]=dfn[u]=++cnt;
for(int i=0;i<len;++i){
int v=g[u][i];
if(v==fr)continue;
if(!dfn[v]){
st.push({u,v});//这里要将边入栈
tarjan(v,u);
low[u]=Min(low[u],low[v]);
if(low[v]>=dfn[u]){//找到割点,u
int cnte=0,cntv=0;
if(low[v]>dfn[u])++ansa;//找到割边,uv
//不能写成low[v]>low[u]
++bcccnt;//用这个来标记点双连通分量,用cnt标记是错的
while(1){
edge e=st.top();
st.pop();
int a=e.u,b=e.v;
bcc[a]=bcccnt;
bcc[b]=bcccnt;
++cnte;
if(a==u&&b==v)break;
}
for(int i=0;i<n;++i)
if(bcc[i]==bcccnt)++cntv;
if(cnte>cntv)ansb+=cnte;
}
}
else if(dfn[u]>dfn[v])
low[u]=Min(low[u],dfn[v]),st.push({u,v});
}
return lowu;
}
int main(){
while(1){
scanf("%d%d",&n,&m);
if(n==0&&m==0)break;
for(int i=0;i<n;++i){
g[i].clear();
}
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(bcc,0,sizeof(bcc));
ansa=ansb=0;
cnt=bcccnt=0;
int u,v;
for(int i=1;i<=m;++i){
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=0;i<n;++i){
if(!dfn[i])tarjan(i,-1);
}
printf("%d %d\n",ansa,ansb);
}
}
标签:连通,点双,int,dfn,low,分量 来源: https://www.cnblogs.com/hetailang/p/16466853.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。