欧拉回路
欧拉回路是指不令笔离开纸面,可画过一个连通图中每条边仅一次
,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
写这个原因
有次crq的课,我太困了,感觉讲的东西我会(那次刚开始课上讲的汉诺塔的递归),
然后我就迷迷糊糊的睡过去了。等我醒来,讲的又是另外一个神奇的东西了,好像
是关于DFS(deep fisrt search 深度优先搜索)。好家伙,上次课的欧拉回路(找师傅)
就听的迷迷糊糊,完了这回又是啥也没听了
解决方案
首先 用邻接矩阵(n*n),来构建图。不用下三角或三角压缩存储,有点麻烦。然后也不用邻接表,这个不知道图 疏不疏 ,而且邻接表对于这个题目操作也不方便。接着用广度优先搜索(BFS)从一个顶点去遍历,看能不能遍历完所有的顶点,即图连不连通.
欧拉回路的判断充要条件是:图为连通图,每个顶点的度为偶数。
连通图
任意连个顶点之间都存在路径,这个路径可以不是直达的,间接的也可以。
本题是对无向图而言,如果是有向图的话,分为强连通图,弱连通图;
路径就要标明方向 <Vstart,Vend>。这里就不展开了!
度
对于无向图而言,度表示,顶点的边数,而对于有向图而言,又分为出度和入度。
有向图的度等于出入度相加。
基本的理论说完了,开始写代码,我在把整体的代码主要分成三部分
- 图的创建和其相对应的基本操作
- 队列的创建和其相对应基本的操作
- 广度优先搜索 查找算法的实现
提醒 最好在每个部分写完之后,就测试这部分的代码有没有出错。方便后面整体代码的调试。
我写的一遍就过了。(●ˇ∀ˇ●)
图
//==========================
//图的结构
typedef struct { //邻接矩阵
int VertexNum; //定点数
int EdgeNum; //边数
int EdgeWeight[MaxNum][MaxNum]; //权重
int Vertex[MaxNum]; //顶点的度数
int isTrav[MaxNum]; //保存遍历标志
}GraphMatrix;
//图的初始化
void InitGraph(GraphMatrix *GM,int n,int m)
{
GM->VertexNum=n;
GM->EdgeNum=m;
memset(GM->EdgeWeight,0,sizeof(GM->EdgeWeight));
memset(GM->Vertex,0,sizeof(GM->Vertex));
}
//输入数据,造图
void CreatGraph(GraphMatrix *GM)
{
int i,j,k;
int Vstart,Vend;
for(i=0;i<GM->EdgeNum;i++)
{
scanf("%d %d",&Vstart,&Vend);
GM->EdgeWeight[Vstart][Vend]=1;
GM->Vertex[Vstart]+=1;
GM->EdgeWeight[Vend][Vstart]=1;
//if(Vstart!=Vend)
GM->Vertex[Vend]+=1;
}
}
//判断图的每个顶点度是否为偶数
int IsEven(GraphMatrix *GM) //even 偶数
{
int i,sum=0;
for(i=1;i<=GM->VertexNum;i++)
sum+=GM->Vertex[i]%2;
if(sum==0) return 1;
else return 0;
}
//图的打印输出,测试图
void OutGraph(GraphMatrix *GM)
{
int i,j;
//输出顶点的信息
printf(" ");
for(i=1;i<=GM->VertexNum;i++)
printf(" %d",i);
printf("\n");
for(i=1;i<=GM->VertexNum;i++)
{
printf("%d ",i);
for(j=1;j<=GM->VertexNum;j++)
{
printf("%d",GM->EdgeWeight[i][j]);
if(j!=GM->VertexNum)printf(" ");
}
printf("\n");
}
}
//==========================
队列
这里 分为队列的主体代码部分,和测试代码部分
主体部分
//============================
typedef struct QNode{ //队列
int data;
struct QNode *next;
}QNode,*QLink;
typedef struct{
QLink first,rear;
}QNodeLink;
//初始化
void InitQueue(QNodeLink *Q)
{
Q->first=(QLink)malloc(sizeof(QNode));
Q->rear=Q->first;
Q->first->next=NULL;
}
//判断队列是否为空
int IsEmpty(QNodeLink *Q)
{
if(Q->first==Q->rear)
return 1;
else return 0;
}
//从队尾进队
void EnQueue(QNodeLink* Q,int x)
{
QLink q=(QLink)malloc(sizeof(QNode));
q->data=x;
q->next=NULL;
Q->rear->next=q;
Q->rear=q;
}
//从队头,出队
void DeQueue(QNodeLink* Q,int *x)
{
//int x;
QLink q;
if(!IsEmpty(Q)) //非空出队
{
q=Q->first;
Q->first=q->next; //下个结点作为头结点
*x=Q->first->data;
free(q);
}
else printf("队列为空\n");
}
//销毁队列,养成好习惯,用完要还回去
void DestoryQueue(QNodeLink *Q)
{
int x;
while(!IsEmpty(Q))
DeQueue(Q,&x);
free(Q->first);
free(Q);
}
测试部分: 这个是很使用的,相当于模板,可以根据需要改。
int main()
{
int x;
char str[10];
QNodeLink *Q=(QNodeLink *)malloc(sizeof(QNodeLink));
InitQueue(Q);
while(scanf("%s",str)!=EOF){
if(!strcmp(str,"en"))
{
scanf("%d",&x);
EnQueue(Q,x);
printf("%d\n",Q->rear->data);
}
else if(!strcmp(str,"de"))
{
if(IsEmpty(Q)) printf("队列为空!!!\n");
else
{
DeQueue(Q,&x);
printf("%d\n",x);
}
}
else if(!strcmp(str,"cls"))
{
system("cls"); //这个要包含头文件 #include<stdlib.h>
}
}
return 0;
}
广度优先搜索(BFS)
这部分要用到队列的思想,和二叉树顺序遍历有点像。
这里的话,我要用到 之前定义过的一个数组 Vertex[ ]来判断,这个顶点是否有没有被访问过,这样就可以减少代码的运行时间,减少资源的开销。
首先把第一个顶点入队,然后出队,访问它的边,这里是二维的数组EdgeWeight[ ][ ],看与之相邻的顶点是否有没有被访问过,如果没有被访问过则,入队。把入队的定标标记为已访问。重复上述操作,直至队列为空,详细看代码。
// 从一个点开始遍历,如果能找到所有的点就算,图连通,否则就不连通,广度优先搜素
int BFS(GraphMatrix *GM)
{
int x,i;
QNodeLink *Q=(QNodeLink *)malloc(sizeof(QNodeLink));
InitQueue(Q);
//从1开始搜
memset(GM->isTrav,0,sizeof(GM->isTrav));
EnQueue(Q,1);
GM->isTrav[1]=1;
while(!IsEmpty(Q))
{
DeQueue(Q,&x);
for(i=1;i<=GM->VertexNum;i++)
{
if(i!=x&&GM->EdgeWeight[x][i]==1&&GM->isTrav[i]!=1) //这里之前错了,0表示为没有访问过
{
EnQueue(Q,i);
GM->isTrav[i]=1;
}
}
}
DestoryQueue(Q);
for(i=1;i<=GM->VertexNum;i++)
if(GM->isTrav[i]==0) return 0;
return 1;
}
完整的代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MaxNum 1000
//==========================
typedef struct { //邻接矩阵
int VertexNum; //定点数
int EdgeNum; //边数
int EdgeWeight[MaxNum][MaxNum]; //权重
int Vertex[MaxNum]; //顶点的度数
int isTrav[MaxNum]; //保存遍历标志
}GraphMatrix;
//==========================
typedef struct QNode{ //队列
int data;
struct QNode *next;
}QNode,*QLink;
typedef struct{
QLink first,rear;
}QNodeLink;
//==========================
void InitQueue(QNodeLink *Q)
{
Q->first=(QLink)malloc(sizeof(QNode));
Q->rear=Q->first;
Q->first->next=NULL;
}
int IsEmpty(QNodeLink *Q)
{
if(Q->first==Q->rear)
return 1;
else return 0;
}
void EnQueue(QNodeLink* Q,int x)
{
QLink q=(QLink)malloc(sizeof(QNode));
q->data=x;
q->next=NULL;
Q->rear->next=q;
Q->rear=q;
}
void DeQueue(QNodeLink* Q,int *x)
{
//int x;
QLink q;
if(!IsEmpty(Q)) //非空出队
{
q=Q->first;
Q->first=q->next; //下个结点作为头结点
*x=Q->first->data;
free(q);
}
else printf("队列为空\n");
}
void DestoryQueue(QNodeLink *Q)
{
int x;
while(!IsEmpty(Q))
DeQueue(Q,&x);
free(Q->first);
free(Q);
}
void InitGraph(GraphMatrix *GM,int n,int m)
{
GM->VertexNum=n;
GM->EdgeNum=m;
memset(GM->EdgeWeight,0,sizeof(GM->EdgeWeight));
memset(GM->Vertex,0,sizeof(GM->Vertex));
}
void CreatGraph(GraphMatrix *GM)
{
int i,j,k;
int Vstart,Vend;
for(i=0;i<GM->EdgeNum;i++)
{
scanf("%d %d",&Vstart,&Vend);
GM->EdgeWeight[Vstart][Vend]=1;
GM->Vertex[Vstart]+=1;
GM->EdgeWeight[Vend][Vstart]=1;
//if(Vstart!=Vend)
GM->Vertex[Vend]+=1;
}
}
int IsEven(GraphMatrix *GM) //even 偶数
{
int i,sum=0;
for(i=1;i<=GM->VertexNum;i++)
sum+=GM->Vertex[i]%2;
if(sum==0) return 1;
else return 0;
}
void OutGraph(GraphMatrix *GM)
{
int i,j;
//输出顶点的信息
printf(" ");
for(i=1;i<=GM->VertexNum;i++)
printf(" %d",i);
printf("\n");
for(i=1;i<=GM->VertexNum;i++)
{
printf("%d ",i);
for(j=1;j<=GM->VertexNum;j++)
{
printf("%d",GM->EdgeWeight[i][j]);
if(j!=GM->VertexNum)printf(" ");
}
printf("\n");
}
}
// 从一个点开始遍历,如果能找到所有的点就算,图连通,否则就不连通,广度优先搜素
int BFS(GraphMatrix *GM)
{
int x,i;
QNodeLink *Q=(QNodeLink *)malloc(sizeof(QNodeLink));
InitQueue(Q);
//从1开始搜
memset(GM->isTrav,0,sizeof(GM->isTrav));
EnQueue(Q,1);
GM->isTrav[1]=1;
while(!IsEmpty(Q))
{
DeQueue(Q,&x);
for(i=1;i<=GM->VertexNum;i++)
{
if(i!=x&&GM->EdgeWeight[x][i]==1&&GM->isTrav[i]!=1) //这里之前错了,0表示为没有访问过
{
EnQueue(Q,i);
GM->isTrav[i]=1;
}
}
}
DestoryQueue(Q);
for(i=1;i<=GM->VertexNum;i++)
if(GM->isTrav[i]==0) return 0;
return 1;
}
int main()
{
int n,m;
int v1,v2;
GraphMatrix *GM;
while(1) //结点和边数
{
scanf("%d",&n);
if(n==0)break;
scanf("%d",&m);
GM=(GraphMatrix *)malloc(sizeof(GraphMatrix));
InitGraph(GM,n,m);
CreatGraph(GM);
//OutGraph(GM);
if(IsEven(GM)&&BFS(GM))
printf("1\n");
else printf("0\n");
free(GM);
//printf("偶数:%d 连通:%d\n",IsEven(GM),BFS(GM));
}
return 0;
}
/*int main()
{
int x;
char str[10];
QNodeLink *Q=(QNodeLink *)malloc(sizeof(QNodeLink));
InitQueue(Q);
while(scanf("%s",str)!=EOF){
if(!strcmp(str,"en"))
{
scanf("%d",&x);
EnQueue(Q,x);
printf("%d\n",Q->rear->data);
}
else if(!strcmp(str,"de"))
{
if(IsEmpty(Q)) printf("队列为空!!!\n");
else
{
DeQueue(Q,&x);
printf("%d\n",x);
}
}
else if(!strcmp(str,"cls"))
{
system("cls"); //这个要包含头文件 #include<stdlib.h>
}
}
return 0;
}
*/
这部分代码可以过题。TZOJ 题号为:3649
请勿直接复制,提交。做人要讲武德┗|`O′|┛ 嗷~~