瞎BB:
✌,破纪录——最短的博客名!!!!
首先,来讲一讲What is 割点?赶紧度娘一下
在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合。
如果某个割点集合只含有一个顶点X(也即{X}是一个割点集合),那么X称为一个割点。
吼吼吼,胆子小的人已经关掉了博客,神马鬼!!!
当然,不要看那些只有大佬看得懂的东西,我们说人话,杨子曰:在一个连通图中,如果把这个点删掉后这个图就不连通了,那么这个点就是割点,也就是说,割点可能有多个,秒懂!话说在这个世界上还有一个东西叫做割边——我觉得智商正常的人都可以猜出这是啥了,我们不多说了
现在我们要讨论的就是割点怎么求了:
先膜拜大佬Tarjan,没错他开发了大量算法(如:一遍DFS求出LCA,缩点(戳我),证明并查集合并的复杂度是O(α(n))(不要问我这是啥))
今天我们要求割点的方法也是他搞出来的——一遍DFS求出所有割点
你先要知道一个东西,叫做DFS树,Look at the 图:
我觉得就不用多解释了吧,实线表示的是真实的DFS顺序,虚线是虽然没有DFS到,但它们两点间确实有边,
首先问个问题,虚线边会不会链接两颗子树(横叉边),Of course not!
如果有这条虚线边,就说明原图中这两点见右边,如果有变那么通过这个点就可以直接DFS的另一个点,那么这两个点就会成父子关系,So,杨子曰:DFS树中没有横叉边,也就是说虚线只会连接到这个节点的祖先
那现在就是怎么求割点了,在DFS的时候分两种情况讨论:
1.这个点是根节点,也就是第一个被遍历的点,如果他的子树个数≥2,他就是割点,应该很好理解,如果删掉这个点,他的子树之间就没有边了
2.这个点不是根节点,那就要看删去以后它的子树是否与这个节点的祖先有边,也就是看这个节点的子树中有没有虚线连到这个节点的祖先,如果有说明即使这个节点删掉了,子树也不会孤立,这个点不是割点,否则这个节点如果删掉,这棵子树就孤立了
那么这时候,我们就可以用low[i]表示以i为根结点的这棵子树中的结点中虚线边连到最高节点,这个最高结点的DFS序(用dfn数组存下)
那么更新low[k](k下一个DFS结点是v)分两种情况
1.k是v的祖先(也就是遍历到k时,v还没有被遍历过)
low[k]=min(low[k],low[v]);
这时候如果low[v]>=dfn[k]那么k就是割点
2.v是k的祖先(也就是遍历到k时,v已经被遍历过了)
low[k]=min(low[k],dfn[v])
OK,完事
poj1144——求割点数量
c++代码:
#include
#include
#include
using namespace std;
int min(int a,int b){
return a<b?a:b;
}
struct Edge{
int next,to;
}edge[10005];
int head[105],low[105],dfn[105],cut[105],nedge,n,res,cnt;
void addedge(int a,int b){
edge[nedge].to=b;
edge[nedge].next=head[a];
head[a]=nedge++;
}
void dfs(int k,int fa){
int son=0;
low[k]=dfn[k]=++cnt;
for (int i=head[k];i!=-1;i=edge[i].next){
int v=edge[i].to;
if (v==fa) continue;
if (low[v]==0){
son++;
dfs(v,k);
low[k]=min(low[k],low[v]);
if ((k==1 && son>=2)||(k!=1 && low[v]>=dfn[k])) cut[k]=1;
}
else low[k]=min(low[k],dfn[v]);
}
}
int main(){
scanf("%d",&n);
while(n!=0){
memset(head,-1,sizeof(head));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(cut,0,sizeof(cut));
nedge=1;
res=0;
cnt=0;
int k;
scanf("%d",&k);
while(k!=0){
int a;
char ch;
scanf("%d%c",&a,&ch);
while(ch!='\n'){
addedge(a,k);
addedge(k,a);
scanf("%d%c",&a,&ch);
}
addedge(a,k);
addedge(k,a);
scanf("%d",&k);
}
dfs(1,1);
for (int i=1;i<=n;i++){
res+=cut[i];
}
cout<<res<<endl;
scanf("%d",&n);
}
return 0;
}
于TJQ高层小区
未经作者允许,严禁转载:https://blog.csdn.net/HenryYang2018/article/details/80158665