算法学习之 图的割点

一.图的割点

先解释一下什么叫图的割点吧,割点就是如果去掉这个点之后无法实现所有点的相互连通,那么这个点就是割点。

二.寻找图的割点

那么给定一张图怎么找到图的割点呢,当然了,所谓割点当然应该是一个图里只有一个强联通分量吧,那么说一下我们大致的算法,我们判断一个节点u是否是割点,就是判读他的子节点中是否存在节点不经过这个节点就无法回到祖先,如果是这样的,那么这个节点就是割点。我们用dfn[u]来记录访问到u的时间戳,low[u]来记录u节点在不经过其父节点所能访问到的最早时间戳(就是第一个能够访问到的祖先节点编号),有了这两个数据,那么根据我们上面的算法我们知道如果 low [i]>= num [cur](i是cur的子节点 ),那么也就是说i没法回到祖先,所以说cur应该是割点

三.数据

n个点m个边,无向图

6 7

1 3

1 4

4 2

3 2

2 5

2 6

5 6

//
//  main.cpp
//  图的割点
//
//  Created by 张嘉韬 on 16/8/29.
//  Copyright © 2016年 张嘉韬. All rights reserved.
//

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=1000;
int min(int a,int b)
{
    if(a<b) return a;
    else return b;
}
int map[maxn][maxn],n,m,x,y,root,flag[maxn],indx,num[maxn],low[maxn];
void dfs(int cur,int father)
{
    int child=0;
    indx++;
    num[cur]=indx;
    low[cur]=indx;
    for(int i=1;i<=n;i++)
    {
        if(map[cur][i]==1)
        {
            if(!num[i])
            {
                dfs(i,cur);// 子节点就去dfs()
                low[cur]=min(low[cur],low[i]);
                if(cur!=root&&low[i]>=num[cur]) flag[cur]=1;
                if(cur==root&&child==2) flag[cur]=1;//虽然未遍历完但是如果有两个两个子节点了那么一定就是割点。
            }
            else if(num[i]&&i!=father)
                low[cur]=min(num[i],low[cur]);
        }
    }
}
int main(int argc, const char * argv[]) {
    freopen("/Users/zhangjiatao/Documents/暑期训练/input.txt","r",stdin);
    memset(map,0,sizeof(map));
    memset(flag,0,sizeof(flag));
    memset(num,0,sizeof(num));
    memset(low,0,sizeof(low));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        map[x][y]=1;
        map[y][x]=1;
    }
    root=1;
    indx=0;
    dfs(1,root);
    for(int i=1;i<=n;i++) cout<<num[i]<<" ";
    cout<<endl;
    for(int i=1;i<=n;i++) cout<<low[i]<<" ";
    cout<<endl;
    for(int i=1;i<=n;i++)
        if(flag[i]) printf("%d\n",i);
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值