写一个c程序判断输入的图是否为哈密尔顿图

实验要求:

    写一个c程序判断输入的图是否为哈密尔顿图。

解题思路:

    首先,要解决的问题是如何把图转化为可以从键盘上输入的内容,并且可以让电脑“读懂”这个图。

    我采用的方式是:把每两个节点之前的关系都输进去,并用数组储存。

    具体实现方法:先输入节点的个数,和边的个数,目的是为了计算需要多少个scanf来读取键盘输入,然后再把每条边两边的节点输入进去,及时地用数组保存,因为做的这个程序是、无向的(也可以改成有向的),所以输入的时候调换两个节点的位置也是可行的(只需要输入两个节点存在关系就可以了)。

    其次,要解决的问题是如何去表示关系,比如1可以指向2,2也可以指向1,也就是1和2之前存在一条边,我采用的是a[x][++num[x]]=y;        a[y][++num[y]]=x;   用num数组给当前节点编号。方便后面遍历边的时候,可以有序不重复地进行。当然,储存关系的时候用链表更加直观、自然,但是用数组更加地顺手,所以就用数组来储存。

把所有对应的关系都输入到数组里面,该数组就构成了一颗树。树的顶点(根节点)不是固定的,因为把任意一个节点作为根节点,都有可能经历所有其他点,并且不重复走边,回到原点。

    接下来该问题就转化成为了如何走遍所有的节点,并回到原地。可以换句话说,就是寻找到最长的路径,并且回到原点,不重复走边。

    所以转化为DFS算法(深度优先搜索Depth-First-Search),意思是寻找树的最大深度路径。DFS算法没有具体的格式化的代码,它更多的是一种思想,通过对节点、路径的标记,来判断路有没有走过(防止被重复走过),通过递归来遍历所有的路径,并从中找到一条最长的路径。

    具体实现方法:

    从第一个节点开始,遍历所有的节点。

    每访问一个节点,调用一次Mydfs方法,并返回flag标记的值(flag为1代表找到了符合要求的路径,flag为0表示这不是哈密尔顿图)

再看Mydfs核心函数,首先这个函数要把main函数的x(遍历的开始位置),n(节点的个数),还有flag标记传入该函数。同时设定上一次访问的节点(为了避免走回头路,而且在最终判断是否构成哈密尔回路有很大的意义)

    Mark数组用来标记节点是否已经被访问,主要是为了在后面的代码中访问其他未访问的节点。每找到一个未标记的点,就把这个节点保存在output数组里面,其中通过length来记录节点具体保存在数组的哪一个位置。如果一条路已经到了尽头,但是无法构成哈密尔回路,那么length就要减一,并且把Mark数组清零,意思是返回到上一个节点,继续寻找该节点对应的没有被访问过的节点。如果还是没有找到这样的节点,那么再返回到上一个节点,以此类推,直到遍历所有的节点为止。该方法用递归来实现。

判断构成哈密尔顿图的条件:

1、下一个点为最初的起点(即回到原点)

2、下一条路是之前没有走过的路

3、路径的长度为n+1(包含了起点,重复计算)

 

 

核心代码:(如果想要完整版的代码请加QQ1228333410)

int Mydfs(int last,int i,int x,int n,intflag)//i表示当前访问节点,last表示上次访问的节点

{

         intj,s;

         Mark[i]=1;//标记为已经访问过

         output[++length]=i;//记录下答案

         for(j=1;j<=num[i];j++)

         {

                   if(!Mark[a[i][j]])//遍历与i相关联的所有未访问过的节点

                   {

                            flag=Mydfs(i,a[i][j],x,n,flag);

                   }

                   if(a[i][j]==x&&a[i][j]!=last&&length==n)//回到起点,构成哈密尔顿图

                   {

                            output[++length]=a[i][j];

                            flag=1;

                            length--;

                            break;

                   }

         }

         length--;

         Mark[i]=0;//回溯

         returnflag;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值