图中欧拉回路数量

一本通上的问题。有一个这样的图:

求其中欧拉回路的数量,且重复的不算(以点来说,2-8-9-10和8-9-2-10是同一个)。

输入:

13 16  //13个点,16条边
9 10
9 8
8 2
10 2
2 3
2 1
1 4
3 4
11 3
11 12
12 13
13 3
4 7
4 5
5 6
6 7

输出:11

思路:以每个点为起点深搜,当再次遇到出发点时cnt++;

难点1:如何判断此条回路是否与某条重复?

解决方式:把曾经成功过的回路存在数组里,有新的成功回路时遍历一番。

难点2:邻接表+无向图,怎样存路径?

解决方式(重点):边的结构体中带上其反向的那条边的序号;

难点3:怎样判断路径?

解决方式:1.如下文代码,把两点间两条边的序号都存下来,先排序,再比较——因为重复的话,与边的顺序无关;

     2.(重点)另一种思路,即把走过的边的bool标记存下来,不仅记录方便(memcpy即可,无需每一步记录),比较时也方便。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,x,y,xnt,la[105];
int str[105][205],sstr=1,snttr[105],snt,qq;//str是回路的记录,sstr是回路数量的记录,snttr是每个回路元素个数的记录 
struct Node{
	int lb,to,next;
}sid[105];
bool bd[205];
void ser(int a)
{
	if(a==qq&&snt)//qq是本次深搜的起点,a是当前点   snt是当前路线的元素个数, &&snt是考虑到未出发时a也是等于qq的 
	{
		bool flag=0;
		memcpy(str[sstr+1],str[sstr],sizeof str[sstr]);//排序前的存放在sstr+1里 
		sort(str[sstr]+1,str[sstr]+snt+1);
		for(int i=1;i<sstr;i++)//sstr是回路数量,现在遍历之前成功的回路 
			if(snttr[i]==snt)//当之前回路的元素个数与现在相等时进入(若不相等则不可能重复) 
			{
				bool fla=1;
				for(int j=1;j<=snt;j++)
					if(str[i][j]!=str[sstr][j])//有一个不相等,就fla=0 
					{
						fla=0;break;
					}
				if(fla)//fla==1说明这个和之前重复了 
				{
					flag=1;break;
				}
			}
		if(!flag)//flag==0说明这个没有和之前重复 
		{
			snttr[sstr]=snt;//存元素个数 
			sstr++;//刚才memcpy的sstr+1变成了sstr,即新的一条路的前面部分还是上一条路的
				   //就像从8字的交点出发,走完下面的圈后,继续向上走,这条继续的路的前面部分还是原来的那个下面的圈
				   //所以这条路成功了也不用return 
		}
		else
		{
			memcpy(str[sstr],str[sstr+1],sizeof str[sstr+1]);//把sstr变回排序前的样子(也许不需要?) 
			memset(str[sstr+1],0,sizeof str[sstr+1]);
		}
	}
	for(int i=la[a];i>0;i=sid[i].next)
		if(!bd[i]&&!bd[sid[i].lb])
		{
			bd[i]=1;
			bd[sid[i].lb]=1;//lb意义见输入过程注释 
			str[sstr][++snt]=i;
			str[sstr][++snt]=sid[i].lb;
			ser(sid[i].to);
			bd[i]=0;
			bd[sid[i].lb]=0;
			str[sstr][snt--]=0;
			str[sstr][snt--]=0;
		}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		xnt++;
		sid[xnt].lb=xnt+1;//用lb表示 9-10边 与 10-9边 这样的关系 
		sid[xnt].to=y;
		sid[xnt].next=la[x];
		la[x]=xnt;
		xnt++;
		sid[xnt].lb=xnt-1;
		sid[xnt].to=x;
		sid[xnt].next=la[y];
		la[y]=xnt;
	}
	for(int i=1;i<=n;i++)
	{
		qq=i;
		memset(bd,0,sizeof bd);
		memset(str[sstr],0,sizeof str[sstr]);
		ser(i);
	}
	printf("%d",sstr-1);
	return 0;
}

  

 

posted on 2017-12-09 16:35  Narh  阅读(208)  评论(0编辑  收藏

导航