找一个欧拉回路的路径问题

来源:互联网 发布:决策分析软件 编辑:程序博客网 时间:2024/05/17 00:50

若一个无向图存在欧拉回路,则图中所有的点的度数都为奇数的点的个数为2或0.

本题中,给定顶点数vertexNum,和每个点的度数degreeNum(当然这里的度数规定为偶数),且vertexNum>degreeNum。

则,必然存在欧拉回路。

#include<stdio.h>#define vertexNum20#define degreeNum10int upLimiteValue(int a, int b);void Drawing(int a[][vertexNum]);void print(int a[][vertexNum]);//定义一个邻接矩阵,记录无向图int matri[vertexNum][vertexNum];//定义一个矩阵,记录每个顶点的度数int ved[vertexNum];void Find_Euler_circuit(int a[][vertexNum]);void main(void){int i,j;//矩阵初始化,两个点有边为1,无边为0for(i=0; i<vertexNum; i++){ved[i]=0;                        /*每个顶点的度数初始化为0*/for(j=0; j<vertexNum; j++){matri[i][j]=0;}}Drawing(matri);print(matri);Find_Euler_circuit(matri);}//构造一个图void Drawing(int a[][vertexNum]){//先构造一棵树,思想:从起点开始,每个点依次与其他顶点相连,直到顶点度数为degreeNum则选择第二层的第一个点作为起点,连接那些还是孤立的//点,依次类推,第三层的第一个起点,第四层的第一个起点,每次都连接那些孤立的点来满足度数,这样可以保证所有的点已经连通。int i,j=1,k;int h;//求一下构造树的高度h=2+upLimiteValue(vertexNum-(degreeNum+1),(degreeNum-1));for(i=0; i<h; i++)            //逐层构造{//查找每层的第一个起点的位置if(i==0 || i==1){k=i;}else if(i==2){k=k+degreeNum;}else{k=k+degreeNum-1;}for(; (ved[k]<degreeNum) && (j<vertexNum); j++){if(a[k][j]==0){a[k][j]=1;a[j][k]=1;ved[k]++;ved[j]++;}}}//把构造出的树中,所有的顶点的度数添加到degreeNumfor(i=0; i<vertexNum; i++){if(ved[i] != degreeNum){for(j=i+1; j<vertexNum && ved[i]!=degreeNum; j++){if(ved[j] != degreeNum && a[i][j]==0) {a[i][j]=1;a[j][i]=1;ved[i]++;ved[j]++;}}}}//补图的过程中,可能有些点的度没有达到规定的度数,需要再进行处理,这里可以得出未达到degreeNum的度一般都在最后,我们可以从后往前遍历for(i=vertexNum-1; ved[i]!=degreeNum; i--){//因为对度数进行补全时,是从前到后,所以未补全的度只能是最后一个点或两个点if(ved[i]%2 != 0)  //假如当前度数是奇数,则前面的度数必然也是奇数{for(j=0; j<i && ved[i]!=degreeNum; j++){for(k=j+1; k<i; k++){if(a[i][j]==0 && a[i][k]==0 && a[i-1][j]==0 && a[i-1][k]==0 && a[j][k]==1){a[j][k]=0;a[k][j]=0;a[i][j]=1;a[j][i]=1;a[i-1][k]=1;a[k][i-1]=1;ved[i]+=1;ved[i-1]+=1;break;}}}}else{for(j=0; j<i && ved[i]!=degreeNum; j++){for(k=j+1; k<i; k++){if(a[i][j]==0 && a[i][k]==0 && a[j][k]==1){a[j][k]=0;a[k][j]=0;a[i][j]=1;a[j][i]=1;a[i][k]=1;a[k][i]=1;ved[i]+=2;break;}}}}}}//寻欧拉回路的思想:从起点开始走,编号小的优先,能得出一个个的小回路,把这些回路上的路径//按每个小回路得出来的先后次序//进行编号,直到所有边都遍历。然后再从起点开始走,先走回路编号的路径,然后选择定点编号小的走,//走完所有边,就能得出Euler回路void Find_Euler_circuit(int a[][vertexNum]){int i,j;int k=2;                              //标记回路号int base=0;                            int vNum=1;int road[(vertexNum*degreeNum)/2+1]={0};//记录每个小回路上的点int start=base;int mark=0;                          //标记已放入回路中的顶点号while(vNum<=(vertexNum*degreeNum)/2){if(ved[base]==0)         //假如顶点的度数已满,则找下一个回路起点,回路号要+1{base=road[++mark];start=base;continue;}for(i=0; i<vertexNum; i++)     //查找一个顶点编号最小的与其相邻的点{if(a[start][i]==1){a[start][i]=k;a[i][start]=k;ved[i]--;ved[start]--;road[vNum]=i;start=i;vNum++;break;}}if(start==base)             //又回到起点,则完成一个回路,{k++;}}printf("*****************************************************\n");print(a);//开始寻找欧拉回路i=0;int bestchoice;int num=0;int jmark;printf("输出欧拉回路路径如下:");while(num<(vertexNum*degreeNum)/2){bestchoice=0;jmark=0;for(j=0; j<vertexNum; j++){if(a[i][j]>bestchoice){bestchoice=a[i][j];jmark=j;}}num++;printf("%d-->%d\t",i,jmark);a[i][jmark]=0;a[jmark][i]=0;i=jmark;}}//求上限值int upLimiteValue(int a, int b){if(a%b==0){return a/b;}else{return a/b+1;}}//打印矩阵void print(int a[][vertexNum]){int i,j;for(i=0; i<vertexNum; i++){for(j=0; j<vertexNum; j++){printf("%4d",a[i][j]);}printf("\n");}}


原创粉丝点击