图的割点

来源:互联网 发布:javascript怎么写插件 编辑:程序博客网 时间:2024/04/30 10:50

如果在图G中去掉一个顶点(自然同时去掉与该顶点相关联的所有边)后,该图的连通分支数增加,则称该顶点为G的割点

这里写图片描述
怎么去找图的割点呢?
我们容易想到的是遍历图,每次删除一个顶点,删除该顶点后,检查图的连通分支数是否增加,如果增加,该点就是割点,否则不是。

大牛们找到了有逼格的算法。。。
用了一个“时间戳”:记录这是第几次遍历的该顶点。和low数组:记录不经过父节点的能回到最小的时间戳。

看了那么久的算法,意思就是说:如果去掉一个顶点,这个顶点的子孩子回不到了它的祖先结点,那么去掉的这个顶点就是割点;所以每次的更新low[]的值,如果low[v]>=num[u];那顶点u就是割点;(类似于一句俗话:没有你爸爸哪有你(嘿嘿你在自己想想这个算法像不像这句话));

关于更新low[]的值在:一直遍历完节点后更新当前节点的low值,如果遍历到的顶点已经遍历过,更新当前节点的low与遍历过的该节点的时间戳比较

与算法书上的代码不同之处:我用的是邻接表

用的是两个数组头结点head[]和放边集的结构体e

关键点在:head[e[i].u]放的是节点e[i].u的第一条边的编号,e[i].next放的是编号为i的“下一条边”的编号、

for(i=边个数)
e[i].next=head[e[i].u];
head[e[i].u]=i;

/*6 71 41 34 23 22 52 65 62 */#include<stdio.h>#include<string.h>#define min(a,b) a<b?a:busing namespace std;int n,m,root;int num[9],low[9],flag[9],index,t; int head[9];struct edge{    int u,v;    int w;    int next;}e[9*9];void dfs(int cur,int f){    int c=0,i,j;    index++;    num[cur]=low[cur]=index;    int k=head[cur];    while(k!=-1)    {        i=e[k].v;        if(num[i]==0)        {            c++;            dfs(i,cur);            low[cur]=min(low[cur],low[i]);            if(cur!=root && low[i] >= num[cur])            {                flag[cur]=1;            }            if(cur==root && c==2)            {                flag[cur]=1;            }        }        else if(i!=f)        {            low[cur]=min(low[cur],num[i]);        }      k=e[k].next;      }}int main(){    int i,j,x,y,t=0;    scanf("%d%d",&n,&m);    memset(head,-1,sizeof(head));    memset(num,0,sizeof(num));    memset(low,0,sizeof(low));    memset(flag,0,sizeof(flag));    for(i=1;i<=n;i++)       {        e[i].w=0;       }    for(i=1;i<=m+m;i+=2)    {        scanf("%d%d",&e[i].u,&e[i].v);        e[i].next=head[e[i].u];        head[e[i].u]=i;        e[i+1].u=e[i].v;        e[i+1].v=e[i].u;        e[i+1].next=head[e[i+1].u];        head[e[i+1].u]=i+1;    }    root=1;    dfs(1,root);    for(i=1;i<=n;i++)    {        if(flag[i]==1)           printf("%d  ",i);    }            return 0;}
0 0
原创粉丝点击