• 图中欧拉回路数量


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

    求其中欧拉回路的数量,且重复的不算(以点来说,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;
    }
    

      

  • 相关阅读:
    【自动化学习】自动化误区
    【uwsgi】Mac下python dyld :Library not loaded 问题解决
    【Mysql】Mac版本navicat premium彻底卸载的终端命令:
    【Mysql学习】锁
    【Pytest学习】重复执行用例插件之pytestrepeat的详细使用
    【Python学习】异常传递
    【Jenkins学习】gitlab自动化触发jenkins任务
    一封程序员的情书
    UNION的使用
    为生成的新行添加默认值
  • 原文地址:https://www.cnblogs.com/Narh/p/8011872.html
Copyright © 2020-2023  润新知