标题:图的割点(邻接矩阵)
只看楼主
巧若拙
Rank: 4
来 自:宁波余姚
等 级:业余侠客
威 望:1
帖 子:159
专家分:273
注 册:2014-8-24
结帖率:46.15%
已结贴  问题点数:20 回复次数:2 
图的割点(邻接矩阵)
本文用邻接矩阵存储图的信息,实现了递归和非递归两种算法。感觉非递归算法还可以有更好的表示,一时想不到,请大牛指点,谢谢!

/*
    Name: 图的割点(邻接矩阵)
    Copyright:
    Author: 巧若拙
    Date: 21-11-14 20:34
    Description:
    在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合。
求割点与桥的算法是R.Tarjan发明的。对图深度优先搜索,定义DFS(u)为u在搜索树(以下简称为树)中被遍历到的次序号(等价于时间戳)。
定义Low(u)为u或u的子树中能通过非父子边追溯到的最早的节点,即DFS序号最小的节点的序号。根据定义,则有:  
Low(u)=Min { DFS(u) ,DFS(v)},其中 (u,v)为后向边(返祖边) 等价于 DFS(v)<DFS(u)且v不为u的父亲节点 Low(v) (u,v)为树枝边(父子边)
一个顶点u是割点,当且仅当满足(1)或(2) :
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)。
本文用邻接矩阵存储图的信息,实现了递归和非递归两种算法。
*/
#include<stdio.h>
#include<stdlib.h>

#define MAXN 26   //最大变量(顶点)数量

typedef char VertexType; //顶点类型由用户自定义
typedef int EdgeType; //边上的权值类型由用户自定义

typedef struct EdgeNode{ //边表结点
    int adjvex;  //邻接点域,存储该顶点对应的下标
//    EdgeType weight; //权值,对于非网图可以不需要
    struct EdgeNode *next; //链域,指向下一个邻接点
} EdgeNode;

typedef struct VertexNode{ //顶点表结点
    VertexType data; //顶点域,存储顶点信息
    EdgeNode *firstEdge; //边表头指针
} VertexNode;

int flag[MAXN] = {0}; //存储顶点是否为割点
int num[MAXN] = {0}; //存储顶点的时间戳信息
int low[MAXN] = {0}; //存储顶点的最小时间戳信息
int index = 0; //用来进行时间戳的递增

void CreateGraph(VertexNode *GL, int n, int m);//创建一个图
void PrintGraph(VertexNode *GL, int n, int m);//输出图
void CutPoint_DFS(VertexNode *GL, int root, int cur, int father);//采用深度优先搜索寻找割点(递归算法)
void CutPoint(VertexNode *GL, int root, int n);//采用深度优先搜索寻找割点(非递归算法)

int main()
{
    int i, m, n;
    VertexNode GL[MAXN];
   
    printf("请输入顶点数量和边数量:\n");
    scanf("%d%d", &n, &m);   
   
    CreateGraph(GL, n, m);//创建一个图
    PrintGraph(GL, n, m);//输出图
   
//    CutPoint_DFS(GL, 0, 0, 0);//从0号顶点开始深度优先搜索寻找割点(递归算法)
    CutPoint(GL, 0, n);//采用深度优先搜索寻找割点(非递归算法)
   
    printf("\n割点为:");
    for (i=0; i<n; i++)//输出所有割点
    {
        if (flag[i] == 1)
            printf("%d ", i);
    }
    printf("\n");
   
    return 0;
}

void CreateGraph(VertexNode *GL, int n, int m)//创建一个图
{
    int i, u, v;
    EdgeNode *e;
   
    for (i=0; i<n; i++)//初始化图
    {
        GL[i].data = i;
        GL[i].firstEdge = NULL;
        num[i] = low[i] = flag[i] = 0;
    }
   
    for (i=0; i<m; i++) //读入边信息(注意是无向图)
    {
        scanf("%d%d", &u, &v);
        
        e = (EdgeNode*)malloc(sizeof(EdgeNode)); //采用头插法插入边表结点
        if (!e)
        {
            puts("Error");
            exit(1);
        }
        e->next = GL[u].firstEdge;
        GL[u].firstEdge = e;
        e->adjvex = v;
        
        e = (EdgeNode*)malloc(sizeof(EdgeNode)); //采用头插法插入边表结点
        if (!e)
        {
            puts("Error");
            exit(1);
        }
        e->next = GL[v].firstEdge;
        GL[v].firstEdge = e;
        e->adjvex = u;
    }
}

void PrintGraph(VertexNode *GL, int n, int m)//输出图
{
    int i, j;
    EdgeNode *e;
   
    for (i=0; i<n; i++)
    {
        printf("%d: ", i);
        e = GL[i].firstEdge;
        while (e)
        {
            printf("<%d, %d>, ", i, e->adjvex);
            e = e->next;
        }
        printf("\n");
    }
    printf("\n");
}
 
void CutPoint_DFS(VertexNode *GL, int root, int cur, int father)//采用深度优先搜索寻找割点(递归算法)
{
    int child = 0;
    EdgeNode *e = GL[cur].firstEdge;
   
    num[cur] = low[cur] = ++index;
    while (e)
    {
        if (num[e->adjvex] == 0) //新结点做儿子
        {
            child++;
            CutPoint_DFS(GL, root, e->adjvex, cur);
            
            low[cur] = (low[cur] < low[e->adjvex]) ? low[cur] : low[e->adjvex];//取最小值
            
            if ((cur != root && num[cur] <= low[e->adjvex])
             || (cur == root && child == 2))
            {
                flag[cur] = 1;
            }
        }
        else if (e->adjvex != father) //与旁系祖先有连接,其实也可以不加这个限制条件,因为如果父亲是自己则low[cur]值不变
        {
            low[cur] = (low[cur] < num[e->adjvex]) ? low[cur] : num[e->adjvex];//取最小值
        }
        
        e = e->next;
    }
}

void CutPoint(VertexNode *GL, int root, int n)//采用深度优先搜索寻找割点(非递归算法)
{
    int Stack[MAXN]; //用来存储当前被处理顶点的栈
    EdgeNode *SF[MAXN], *e;
    int child[MAXN] = {0}; //存储顶点的儿子数量
    int u, v, top = 0;
   
    for (u=0; u<n; u++)//初始化SF
        SF[u] = GL[u].firstEdge;
        
    Stack[top] = root;
    num[root] = low[root] = ++index;
    while (top >= 0)
    {
        e = SF[Stack[top]];
        if (e)
        {
            SF[Stack[top]] = e->next; //指向下一条边
            if (num[e->adjvex] == 0)
            {
                child[Stack[top]]++;
                Stack[++top] = e->adjvex;
                low[e->adjvex] = num[e->adjvex] = ++index;
            }
            else
            {
                low[Stack[top]] = (low[Stack[top]] < num[e->adjvex]) ? low[Stack[top]] : num[e->adjvex];//取最小值
            }
        }
        else
        {
            if (top > 0)
            {
                u = Stack[top-1];
                v = Stack[top];
                low[u] = (low[u] < low[v]) ? low[u] : low[v];
                if ((u != root && low[v] >= num[u])
                 || (u == root && child[u] == 2))
                {
                    flag[u] = 1;
                }
            }
            top--;
        }
    }        
}
搜索更多相关主题的帖子: Copyright 信息 
2014-11-21 21:17
诸葛欧阳
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:流年
等 级:贵宾
威 望:82
帖 子:2790
专家分:14619
注 册:2014-10-16
得分:10 
实在无能为力,抱歉帮不了你

一片落叶掉进了回忆的流年。
2014-11-22 17:37
longwu9t
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:6
帖 子:732
专家分:2468
注 册:2014-10-9
得分:10 
这应该发到数据结构和算法那边了……

Only the Code Tells the Truth             K.I.S.S
2014-11-22 19:57



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-438975-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.397231 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved