自己写的无向连通图求割点和桥的代码

//求无向连通图的割点和桥 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;


#define MaxSize 1000
int pre[MaxSize];  //记录节点在dfs生成树中的编号,并可以用来判定节点是否已访问
int iscut[MaxSize],isbrige[MaxSize][MaxSize]; //记录顶点和边是否是割点和桥
int low[MaxSize];  //记录每个节点所能返回的祖先的最小编号 
int n,m,dfs_clock;  //图的顶点数和边数,记录节点再dfs森林中的编号 
vector<int> map[MaxSize];  //vector模拟图的邻接表


//利用图的邻接表建立图 
void Create()
{
int i,j,k1,k2;
cin>>n>>m;
for(i=0;i<n;i++)
    map[i].clear();  //记得清空 
for(i=0;i<m;i++)
{
cin>>k1>>k2;
map[k1].push_back(k2);
map[k2].push_back(k1);




//首先对于割点:
  //(1): 若u是根节点,如果u的儿子数大于1,则u一定是割点
  //(2):若u不是根节点当且仅当存在父子边(u,v)且pre[u]<=low[v] 
//然后对于割边
   //必须满足存在父子边(u,v)且pre[u]<low[v],则(u,v)为一条割边 


/*对于求low值主要是依据:low[u]=min
{
 pre[u];  //节点自己在dfs森林中的编号 
 pre[v];  //若存在反向边(u,v),则要考虑v的编号
 low[v];  //考虑u的儿子v的low值 
}程序用递归实现这个过程*/


//传入的fa是u的父节点,根节点的父节点指定为负数 
int dfs(int u,int fa)  
{
     int lowu=pre[u]=++dfs_clock; //lowu代表要求节点的low值,初始化为pre[u]的值
int child=0;  //记录当前节点的儿子数
int i,j,k;
k=map[u].size();
for(i=0;i<k;i++)  //依次检查u的每一个子节点
{
     int v=map[u][i];
 if(!pre[v])  //(u,v)为父子边情况
 {
      child++;
int lowv=dfs(v,u);  //计算儿子节点的low值
lowu=min(lowu,lowv);//用儿子节点的low值更新父节点的low值
if(lowv>=pre[u])  //利用儿子节点的low值判断自身是否为割点 
    iscut[u]=1;
    if(lowv>pre[u])  //判断(u,v)是否为割边
    isbrige[u][v]=1; 
 } 
 else if(pre[v]&&v!=fa)  //是反向边情况,但要排除反向父子边的情况
      lowu=min(lowu,pre[v]); //用pre[v]更新lowu的值 

if(fa<0&&child==1)  //对根节点情况进行特判 
     iscut[u]=0; 
low[u]=lowu;  //记录最终结果 
return lowu;



//初始化函数 
void Init()
{
memset(iscut,0,sizeof(iscut));
memset(isbrige,0,sizeof(isbrige));
memset(pre,0,sizeof(pre));
dfs_clock=0; 
}


int main()
{
while(1)
{
int i,j,k;
Create();
Init();
dfs(0,-1);  //对于无向图连通图来说,可以从任意一点遍历整个图
cout<<"割点有:"<<endl;
for(i=0;i<n;i++)
    if(iscut[i])
   cout<<i<<" ";
cout<<endl;
cout<<endl<<"桥有:"<<endl;
    for(i=0;i<n;i++)
   for(j=0;j<n;j++)
  if(isbrige[i][j]) 
            cout<<i<<" "<<j<<endl;
cout<<endl;
}
  return 0;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值