平面中存在多个点,求连通点中环的个数

 参加某面试遇到的题目,当时只有一个想法,也没有写对,回来后自己想了两个思路,如有错误请大家给与指正。
VS2010可以运行通过。

1.深度优先搜寻遍历法(结果不准确)

存储结构:邻接链表

判断图中是否有环的思想:

如果存在回路,则必存在一个子图,是一个环路。

找出环个数和环中元素的思想:

遍历过程中记录节点个数,当节点个数大于三个,并且当前被遍历节点数和首节点相同,则求得该环。

2.回溯法搜寻遍历法

存储结构:邻接矩阵

判断图中是否有环的思想:

如果存在回路,则必存在一个子图,是一个环路。

找出环个数和环中元素的思想:

把度为1 的结点都删除后,剩下的均为环中元素,之后进回溯法遍历。

 

两种方法都是先求得所有可能的环,这其中有重复环,文中使用节点字母组成字符串,最后对字符串排序后,删除重复字符串,

因此程序中输出的结果是这些节点组成字符串的排序后值。

具体程序如下所示

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

//图的个数
const int Num=13;
//边连接情况
int path[13][2]={{0,1},{0,2},{0,5},{0,11},{1,12},{3,4},{6,7},{6,10},{6,8},{7,10},{11,9},{11,12},{9,12}};
//存储所有遍历到的环,最后根据环字符串,删除重复环
vector<string> AllCircle,AllCircle2;
//回溯法求解时,剔除度为一的节点后剩余节点
vector<int> NewNode;

/*******************************以下为深度优先遍历(答案不太对)*****************************************/
//深度优先遍历 部分
struct Link
{
	int data;
	int dim;
	Link* next;
};
//邻接链表存储
Link* CreateLink()
{
	Link* MyLink=new Link[Num];
	for(int i=0;i<Num;++i)
	{
		MyLink[i].data=i;
		MyLink[i].next=NULL;
		MyLink[i].dim=0;
	}
	for(int i=0;i<_countof(path);++i)
	{
		int a,b;
		a=path[i][0];
		b=path[i][1];
		Link* Linka=new Link;
		Linka->data=b;
		Linka->dim=0;
		Linka->next=MyLink[a].next;
		MyLink[a].next=Linka;
		MyLink[a].dim++;
		Link* Linkb=new Link;
		Linkb->data=a;
		Linkb->dim=0;
		Linkb->next=MyLink[b].next;
		MyLink[b].next=Linkb;
		MyLink[b].dim++;
	}
	/*cout<<"Output of link table:"<<endl;
	for (int i=0;i<Num;++i)
	{
		Link *p=&MyLink[i];
		cout<<char(p->data+'A')<<" "<<p->dim<<" ";
		while(p->next!=NULL)
		{
			p=p->next;
			cout<<char(p->data+'A')<<" ";
		}
		cout<<endl;
	}*/
	return MyLink;
}

//深度优先遍历
void DFS(int n,Link* MyLink,bool* visit,vector<char>& Circle)
{
	Link *Tmp=&MyLink[n];
	Circle.push_back(n+'A');
	visit[n]=true;
	while(Tmp->next!=NULL)
	{
		int nn=Tmp->next->data;
		int dim=MyLink[nn].dim;
		if(!visit[nn]&&dim>1)
			DFS(nn,MyLink,visit,Circle);
		else
		{
			if((nn+'A')==Circle[0]&&Circle.size()>2)
			{
				AllCircle.push_back(string(Circle.begin(),Circle.end()));
			}
		}
		Tmp=Tmp->next;
	}
}
//深度优先遍历处理函数
void DFSSearch()
{
	Link* MyLink=CreateLink();
	for (int i=0;i<Num;++i)
	{
		if(MyLink[i].dim>1)
		{
			vector<char> Circle;
			bool* visit=new bool[Num];
			memset(visit,0,Num);
			DFS(i,MyLink,visit,Circle);
			//cout<<string(Circle.begin(),Circle.end())<<endl;
		}
	}
	vector<string> TmpCircle=AllCircle;
	for (int i=0;i<TmpCircle.size();++i)
	{
		sort(TmpCircle[i].begin(),TmpCircle[i].end());
	}
	sort(TmpCircle.begin(),TmpCircle.end());
	vector<string>::iterator it=unique(TmpCircle.begin(),TmpCircle.end());
	TmpCircle.erase(it,TmpCircle.end());
	cout<<"深度优先遍历所求环组合"<<endl;
	for (int i=0;i<TmpCircle.size();++i)
	{
		cout<<TmpCircle[i]<<" ";
	}
	cout<<endl;
}

/*******************************以下为回溯法遍历(请大家给予意见)*****************************************/
//判断节点是否选择正确
bool IsSafe(int m,int n,int** path,vector<int>& Circle)
{
	if (n>0)
	{
		if(n==1)
		{
			if(!path[m][Circle[n-1]]||m==Circle[n-1])
				return false;
		}
		else
		{
			if(!path[m][Circle[n-1]]||m==Circle[n-1]||m==Circle[n-2])
			{
				return false;
			}
			if(count(Circle.begin(),Circle.end(),m)>0&&Circle[0]!=m)
			{
				return false;
			}
		}
	}
	return true;
}
//回溯寻找
void FindCircle(int n,int** path,vector<int>& Circle,int NewLen)
{
	if(Circle.size()>2&&Circle[n-1]==Circle[0])
	{
		string TmpCircle;
		for (int i=0;i<Circle.size()-1;++i)
		{
					TmpCircle+=char(NewNode[Circle[i]]+'A');
		}
		AllCircle2.push_back(TmpCircle);
		//cout<<TmpCircle<<endl;
		return;
	}
	else
	{
		int i,j(0);
		for(i=j;i<NewLen;++i)
		{
			if(IsSafe(i,n,path,Circle))
			{
				++n;
				Circle.push_back(i);
				FindCircle(n,path,Circle,NewLen);
				--n;
				Circle.pop_back();
				if(n==0)
					++j;
			}
		}
	}
}
//回溯法处理函数
void RecallSearch()
{
	int NodeDim[Num]={0};
	int a,b;
	for(int i=0;i<_countof(path);++i)
	{
		a=path[i][0];
		b=path[i][1];
		NodeDim[a]++;
		NodeDim[b]++;
	}
	for(int i=0;i<Num;++i)
	{
		if(NodeDim[i]>1)
		{
			NewNode.push_back(i);
			//cout<<char(i+'A')<<endl;
		}
	}
	int Len=NewNode.size();
	int **NewPath=new int*[Len];
	for(int i=0;i<Len;++i)
		NewPath[i]=new int [Len]();
	vector<int>::iterator ita,itb;;
	for(int i=0;i<_countof(path);++i)
	{
		a=path[i][0];
		b=path[i][1];
		if( (ita=find(NewNode.begin(),NewNode.end(),a))!=NewNode.end()
			&&(itb=find(NewNode.begin(),NewNode.end(),b))!=NewNode.end() )
		{
			NewPath[ita-NewNode.begin()][itb-NewNode.begin()]=1;
			NewPath[itb-NewNode.begin()][ita-NewNode.begin()]=1;
		}
	}
	/*for(int i=0;i<Len;++i)
	{
		for(int j=0;j<Len;++j)
			cout<<NewPath[i][j]<<" ";
		cout<<endl;
	}*/
	vector<int> Circle;
	FindCircle(0,NewPath,Circle,Len);
	vector<string> TmpCircle=AllCircle2;
	for (int i=0;i<TmpCircle.size();++i)
	{
		sort(TmpCircle[i].begin(),TmpCircle[i].end());
	}
	sort(TmpCircle.begin(),TmpCircle.end());
	vector<string>::iterator it=unique(TmpCircle.begin(),TmpCircle.end());
	TmpCircle.erase(it,TmpCircle.end());
	cout<<"回溯法遍历所求环组合"<<endl;
	for (int i=0;i<TmpCircle.size();++i)
	{
		cout<<TmpCircle[i]<<" ";
	}
	cout<<endl;
	for(int i=0;i<Len;++i)
		delete []NewPath[i];
	delete NewPath;
}

int main()
{
	DFSSearch();
	RecallSearch();
	system("pause");
	return 0;
}

 

测试:

要输入的图:

 

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值