可图画,连通图和欧拉图的判断

2023-11-02 09:20
文章标签 判断 连通 欧拉 图画

本文主要是介绍可图画,连通图和欧拉图的判断,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

可图画,连通图和欧拉图的判断

语言使用c++

实验目的:

1、掌握可简单图化的定义及判断方法;
2、掌握连通图、欧拉图的判断方法;
3、掌握欧拉回路的搜索方法;
4、了解欧拉图的实际应用。

实验要求

1、给定一非负整数序列(例如:(4,2,2,2,2))。
2、判断此非负整数序列是否是可图化的,是否是可简单图化的。
3、如果是可简单图化的,根据Havel定理过程求出对应的简单图,并输出此简单图的相邻矩阵(默认第i行对应顶点vi)。
4、判断此简单图是否是连通的。
如果是连通图,判断此图是否是欧拉图。如果是欧拉图,请输出一条欧拉回路(输出形式如:v2->v1->v5->v3->v4->v5->v2)。

输入限定(较为简单的部分,不做解释)

先讲一下这里实现了一个点类

class point
{
private:int* other; //数组int pointId;//点的名字 v1/v2/....int border;//这个点有几条边int s;
public:point() {border = 0;pointId = 0;other = NULL;}void setpoint(int n, int id,int bor){other = new int[n]();pointId = id;border = bor;s = n;}int getborder(){return border;}void setother(int i){//cout << pointId<<endl;other[i] = 1;}void printSelf(){for (int i = 0; i < s; i++){cout << other[i]<<" ";}cout << endl;}int* returnOther(){return other;}int returnCon(int i){return other[i];}
};

这个数组就是为了判断这个点和剩下的点是否联通,联通为1,不连通为0;

1.实现判断简单图

两条判定定理 首先使用握手定理 在判断最大度小于n
(因为是(4,2,2,2,2)这样输入的,所以去一个字符把逗号读走,最后读到)结束

	while (Yes != 41)//先读进来{cin >> n>> Yes;arr[i] = (int)n;i++;sum += n;}
bubble_sort(arr, i);//冒泡
if(sum%2==0){if (arr[0] > i - 1){cout << "不可图画" << endl;return 0;}

#2.用fleury判断是否可简单图画并且生成临接矩阵

int big;//主要的指针int tmp;//每次右移的数量int simple = 0;//0代表可 1代表不可for (big = 0; big < i-1; big++){tmp=arr[big];arr[big] = 0;for (int z=0; z < tmp; z++){arr[big + z + 1]--;//建立边的联系,应该是交换完的数组应该在反过来/*cout << position[big + z + 1]<<"++"<<endl;*/points[position[big + z + 1]].setother(position[big]);points[position[big]].setother(position[big + z + 1]);}//检查剩下的数有没有负数for (int a = big+1; a < i; a++){if (arr[a] < 0){simple = 1;cout << "可图画,不可简单图画" << endl;return 0;break;}}//把数组在排序一下newbubble_sort(arr, position, i - big+1, big + 1);if (simple == 1) break;}}else{cout << "不可图画"<<endl;return 0;simple = 1;}/*for (int a = 0; a < i; a++){points[a].printSelf();}*/if (simple == 0){for (int a = 0; a < i; a++){points[a].printSelf();}}

这里主要讲下思路,这里定义了两个数组用来代替二维数组,然后设置一个点类(所以写算法时最好别写类,很难写),我们在上一步已经已经使用冒泡排序,所以现在是一个从大到小的数组,排序完要实例化对象生成n个点
对于输入样例:
(4,2,2,2,2)来说,
创建对象 v1有四条边,v2有两条边,v3,v4…

我们要在建立一组数组,来存放他的位置(判断交换位置后到底是v几),因为后面减的过程中可能会出现后面的比前面的大,这时候就要重新排序,所以为了防止位置错误,这里新建一个position数组
例:arr[4,2,2,2,2]
position[0,1,2,3,4]

都创建完成后我们开始进入循环
我们首先应该读到 4 也就是对应数组arr[0],然后对于后面4个点来说 ,每个点的度-1,并且说明后面四个点和度为4的点有连接.这时候要在点类中设置,就是说 v2,v3,v4,v5都要用setborde方法和v1建立联系,同样的v1和他们的联系也要set

points[position[big + z + 1]].setother(position[big]);
points[position[big]].setother(position[big + z + 1]);

这里为什么是position[big]?
此时没有交换 后面会讲这个问题.

然后一个过程就完成了,此时把不要的放弃对除第一点以外的点排序,注意数组的长度也变了.
此时应改为
arr[1,1,1,1]
position[1,2,3,4]
在进行一部循环
此时剩下数为:
arr[0,1,1]
position[2,3,4]
此时来讲为什么要用position这个数组,我们对他排序完
arr[1,1,0]
position[3,4,0]
这是我们用position[n]就能知道到底是哪两个点之间有联系,不然就会变成v3和v4之间的联系就错了.

2.判断是否为联通图

可能打竞赛的同学知道很多方法,这里我说两个普通吧,毕竟我也不打不懂啊

简单的方法就说算连通矩阵的n-1次方,除对角线以为不可能出现一个0,也可以在简单一点对于一行,除它自己以外存在一个0,说明是不连通的,但是c++实现矩阵的乘法也太麻烦了(不太懂的同学可以看看离散数学书)

可以参考第二种方法
我提供思路和部分代码讲解,因为我实在写的太不规范了,如果后面有时间我会重写一个简单的

//上代码
void check(matrix* A, int i,int arr[])
{for (int a=0; a < i; a++){int f = 0, l = 0,success;if (arr[a] == 1){f = 0;while (true){if (A->get(f, l) != 0){success = 0;int tmp1 = f;A->setdate(f, l, 0);A->setdate(l, f, 0);arr[l] = 1;check(A, i, arr);f = l;//如果过去什么也没有 在回来for (int a = 0; a < i; a++){if (A->get(f, a) != 0){success = 1;break;}}if (success == 0) f = tmp1;l = 0;}else{l++;if (l == i) break;}}}}
}
int recursive(matrix* A,int i)
{int f = 0, l = 0,n=0;int success;int *judge;judge = new int[i]();judge[0] = 1;while (true){if (A->get(f, l) != 0){success = 0;int tmp1 = f;A->setdate(f, l, 0);A->setdate(l, f, 0);judge[l] = 1;f = l;//如果过去什么也没有 在回来for (int a = 0; a < i; a++){if (A->get(f, a) != 0){success = 1;break;}}if (success == 0) f = tmp1;l = 0;}else{l++;if (l == i) break;}}check(A, i, judge);for (int a = 0; a < i; a++){if (judge[a] == 0)return 1;}return 0;
}

就是一个简单的递归
讲一下主要思路,我们都从v1开始找,如果找完还有v1不能连通到的地方,就说明是不连通的,我们定义一个数组judge[]只要是能找到我们都设置为1

首先v1是1,judge[0]=1;然后进去找v1相连的边;我们还是拿(4,2,2,2,2)来讲
首先看着联通矩阵
0 1 1 1 1
1 0 1 0 0
1 1 0 0 0
1 0 0 0 1
1 0 0 1 0
v1 找到和v2 是相连的就把这个边删了,所以消除(0,1)和(1,0)的1
并且这里judge[1]=1;然后找v2的
0 0 1 1 1
0 0 1 0 0
1 1 0 0 0
1 0 0 0 1
1 0 0 1 0
找完再找v3
0 0 1 1 1
0 0 0 0 0
1 0 0 0 0
1 0 0 0 1
遍历完成后,我们需要考虑如果v1->v2->v3 但v2->v4;
我们没有考虑到这种情况,所以我们对我们之要在进行循环判断我们之前这个连通路径还能不能有其他路径
这里使用了递归调用,如果我们发现的一个新的点,这个点可能会连通很多点,所以还有对这个点进行递归.(这里后面找路径也是这种思路)

最后但我们不能在发现新的点退出,如果这个数组还有0,则不能连通;

判断是否为欧拉图

很简单不多说

找到一条欧拉回路

这里前面找连通的时候给了我思路,这里我们使用欧拉图的一个冲要条件,n个不相交的圈的并,我们如果像上面的方法一样,因为是欧拉图,所以我们一定找到一条回路,此时我们就把当作大圈
在这里插入图片描述
然后遍历这个圈上所有的点,要是有新的路径可以开始,也一定是个圈,当存在一个新圈的时候要在找一遍所以要进行递归

void move(int* first, int star,int n)
{for (int i = 0; i < n; i++){first[star + i + n] = first[star + n];}
}
void add(int* first, int *last, int n,int sum)
{int i;n = last[0];for (i = 0; i < sum; i++){if (first[i] == last[0]){move(first, i, n);for (int a = 0; a < n; a++){first[i + a] = last[a];}}}
}void checkroad(matrix* A, int i, int arr[],int road[],int sum)
{int f = 0, l = 0, success=0, n = 0;int* tmp;tmp = new int[sum]();for (int a = 0; a < i; a++){if (arr[a] == 1){f = a;n = 0;tmp[n] = a;while (true){if (A->get(f, l) != 0){success = 1;int tmp1 = f;A->setdate(f, l, 0);A->setdate(l, f, 0);arr[l] = 1;f = l;n++;tmp[n] = l+1;l = 0;}else{l++;if (l == i){l = 0;break;}}}}if (success == 1){checkroad(A, i, arr, road, sum);//把这个新数组加进来add(road, tmp, n, sum);}}
}
void findroad(matrix* A, int i, int road[],int sum)
{int f = 0, l = 0, n = 0;int success;int* judge;judge = new int[i]();road[0] = 1;judge[0] = 1;while (true){if (A->get(f, l) != 0){n++;road[n] = l+1;success = 0;int tmp1 = f;A->setdate(f, l, 0);A->setdate(l, f, 0);judge[l] = 1;f = l;l = 0;//如果过去什么也没有 就停下来for (int a = 0; a < i; a++){if (A->get(f, a) != 0){success = 1;break;}}if (success == 0){break;}}else{l++;if (l == i) break;}}checkroad(A, i, judge,road,sum);}

当然还有找到路径还得存下来,所以还有一下修改数组的方法

最后看看结果

在这里插入图片描述
第一次写博客可能还有很多不足,后面有时间会整理了代码放github上

这篇关于可图画,连通图和欧拉图的判断的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/329638

相关文章

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

【408DS算法题】039进阶-判断图中路径是否存在

Index 题目分析实现总结 题目 对于给定的图G,设计函数实现判断G中是否含有从start结点到stop结点的路径。 分析实现 对于图的路径的存在性判断,有两种做法:(本文的实现均基于邻接矩阵存储方式的图) 1.图的BFS BFS的思路相对比较直观——从起始结点出发进行层次遍历,遍历过程中遇到结点i就表示存在路径start->i,故只需判断每个结点i是否就是stop

linux 判断某个命令是否安装

linux 判断某个命令是否安装 if ! [ -x "$(command -v git)" ]; thenecho 'Error: git is not installed.' >&2exit 1fi

欧拉系统 kernel 升级、降级

系统版本  cat  /etc/os-release  NAME="openEuler"VERSION="22.03 (LTS-SP1)"ID="openEuler"VERSION_ID="22.03"PRETTY_NAME="openEuler 22.03 (LTS-SP1)"ANSI_COLOR="0;31" 系统初始 kernel 版本 5.10.0-136.12.0.

shell循环sleep while例子 条件判断

i=1# 小于5等于时候才执行while [ ${i} -le 5 ]doecho ${i}i=`expr ${i} + 1`# 休眠3秒sleep 3doneecho done 参考 http://c.biancheng.net/cpp/view/2736.html