求一个连通图的割点,割点的定义是,如果除去此节点和与其相关的边,图不再连通,描述算法

参考:http://blog.csdn.net/cxllyg/article/details/7610265

 

题目:求一个连通图的割点,割点的定义是,如果除去此节点和与其相关的边,图不再连通,描述算法。

分析:

1. 最简单也是最直接的算法是,删除一个点然后判断连通性,如果删除此点,图不再连通,则此点是割点,反之不是割点(图的连通性一般通过深搜来判定,是否能一次搜索完 全部顶点);

2. 通过深搜优先生成树来判定。从任一点出发深度优先遍历得到优先生成树,对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类割点的特性:

     (1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为割点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林;

     (2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为割点。因为删去v,则其子树和图的其它部分被分割开来。

仍然利用深搜算法,只不过在这里定义visited[v]表示为深度优先搜索遍历图时访问顶点v的次序号,定义low[v]=Min{visited[v],low[w],visited[k]},其中w是顶点v在深度优先生成树上的孩子节点;k是顶点v在深度优先生成树上由回边联结的祖先节点。

   割点判定条件:如果对于某个顶点v,存在孩子节点w且low[w]>=visited[v],则该顶点v必为关节点。因为当w是v的孩子节点时,low[w]>=visited[v],表明w及其子孙均无指向v的祖先的回边,那么当删除顶点v后,v的孩子节点将于其他节点被分割开来,从来形成新的连通分量。

 

#include <iostream>
#include <string>
using namespace std;

#define MAX_NUM 10

typedef struct EdgeNode
{
	int adjvex;
	struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode
{
	string data;
	EdgeNode *first;
}VertexNode,List[MAX_NUM];

typedef struct Graph
{
	List vertexnode;
	int num_vertex;
	int num_edge;
}Graph;

int count = 0;
int visit[MAX_NUM];
int low[MAX_NUM];

int get_location(Graph g, string s)
{
	for(int i=0;i<g.num_vertex;i++)
	{
		if(s == g.vertexnode[i].data)
			return i;
	}
	return -1;
}

void create_graph(Graph &g)//创建无向图
{
	int i,j,k;
	string s1,s2;
	cout<<"请输入节点和边的个数:";
	cin>>g.num_vertex>>g.num_edge;
	cout<<"请输入节点:";
	for(i=0;i<g.num_vertex;i++)
	{
		cin>>g.vertexnode[i].data;
		g.vertexnode[i].first=NULL;
	}
	cout<<"请输入边:"<<endl;
	for(k=0;k<g.num_edge;k++)
	{
		cin>>s1>>s2;
		i = get_location(g,s1);
		j = get_location(g,s2);

		EdgeNode *p = new EdgeNode();
		p->adjvex = j;
		p->next = g.vertexnode[i].first;
		g.vertexnode[i].first = p;

		EdgeNode *q = new EdgeNode();
		q->adjvex = i;
		q->next = g.vertexnode[j].first;
		g.vertexnode[j].first = q;
	}
}

void find_core(Graph g, int index)
{
	int min,w;
	EdgeNode *p;
	min = visit[index] = ++count;
	bool flag = false;

	for(p=g.vertexnode[index].first;p;p=p->next)
	{
		w = p->adjvex;
		if(visit[w]==0)
		{
			find_core(g,w);
			if(low[w] < min)
				min = low[w];
			else if(low[w] >= min)
			{
				if(flag == false)//防止重复打印
				{
					cout<<g.vertexnode[index].data<<" ";
					flag = true;
				}
			}
		}
		else if(visit[w] < min)
		{
			min = visit[w];
		}
	}
	low[index]=min;
}

void find(Graph g)
{
	int i;
	for(i=0;i<MAX_NUM;i++)
	{
		visit[i]=0;
		low[i]=65536;
	}
	visit[0] = 1;//从v0出发
	low[0] = 1;
	count=1;
	EdgeNode *p = g.vertexnode[0].first;
	int index = p->adjvex;
	find_core(g,index);
	if(count < g.num_vertex)//v0至少有两个子图
	{
		cout<<g.vertexnode[0].data<<" ";//v0是一个割点
		p = p->next;
		while(p)//遍历其它的子图
		{
			index = p->adjvex;
			if(visit[index]==0)
				find_core(g,index);
			p = p->next;
		}
	}
}

int main()
{
	Graph g;
	create_graph(g);
	cout<<"割点如下:"<<endl;
	find(g);
	cout<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值