可简单图化、连通图、欧拉图和哈密顿图的判断
1、掌握可简单图化的定义及判断方法;
2、掌握连通图、欧拉图的判断方法;
3、掌握欧拉回路的搜索方法;
4、了解欧拉图的实际应用。
1、给定一非负整数序列(例如:(4,2,2,2,2))判断此非负整数序列是否是可图化的,是否是可简单图化的。
2、如果是可简单图化的,根据Havel定理过程求出对应的简单图,并输出此图。
3、判断此简单图是否是连通的。
4、如果是连通图,判断此图是否是欧拉图。如果是欧拉图,请输出一条欧拉回路(输出形式如:v2→v1→v5→v3→v4→v5→v2)。
根据握手定理,一个图可图化,则图的总度数为偶数
def judge_graph(l: list) -> bool:
return not sum(l) % 2
在可图画的基础上,根据Havel定理,设 n-1 ≥ d1 ≥ d2 ≥ … ≥ dn ≥0 , 则d可简单图化当且仅当 d’ = (d2-1, d3-1, …, dd1+1-1, dd1+2, …, dn) 可简单图化。
def judge_simpleGraph(l: list) -> bool:
t = copy.deepcopy(l)
for i in range(len(t)):
t.sort(reverse=True)
# 如果di为0,则不需要再进行操作
if t[i] == 0:
break
# 判断di后方是否有di个数
if i + 1 + t[i] > len(t):
return False
# 对di后面每一个数减一,如果有负数,则不可简单图化
for j in range(i + 1, i + 1 + t[i]):
t[j] -= 1
if t[j] < 0:
return False
return True
同样根据Havel定理,在对di后面的数减一的时候,代表di与其相邻,则在相邻矩阵中对应处置1
def cal_simple_graph(l: list) -> list:
# i用于保存是哪个点,l[i]表示其度数
t = [[i, l[i]] for i in range(len(l))]
# 构建全0相邻矩阵
matrix = [[0] * len(l) for _ in range(len(l))]
for i in range(len(l)):
# 根据度数排序
t.sort(reverse=True, key=lambda x: x[1])
# 对相应的点减少度数,并矩阵对应位置置1
for j in range(i + 1, i + 1 + t[i][1]):
matrix[t[i][0]][t[j][0]] = 1
matrix[t[j][0]][t[i][0]] = 1
t[j][1] -= 1
return matrix
根据返回的矩阵输出
m = cal_simple_graph(dushu)
print("相邻矩阵为:")
for i in m:
for j in i:
print(str(j) + " ", end="")
print()
先根据相邻矩阵求邻接矩阵,对邻接矩阵求n次幂,如果所得矩阵中,没有等于0的数,则改图连通。
def liantong(l: list) -> bool:
n = copy.deepcopy(l)
# 求邻接矩阵
for i in range(len(n)):
n[i][i] = 1
# 求邻接矩阵的n次幂
t = numpy.array(n)
for _ in range(len(n)):
t = numpy.dot(t, n)
t = list(t)
# 判断结果中是否有非零数
for i in range(len(n)):
for j in range(len(n)):
if t[i][j] == 0:
return False
return True
根据欧拉图的充要条件,如果G是欧拉图,则G是连通的,且G中点都为偶数度,只需对相邻矩阵的每一行求和判断其是否为二的倍数即可。
def oular(l: list) -> bool:
return not sum([1 for i in l if sum(i) % 2 != 0])
确定欧拉图中的一个顶点,选择一个与其关联的点,并删除之间的边,再对选择的这个点执行相同的操作,直到全部的边被删除,再将点入栈,输出的时候再将入栈的点一个个弹出。
def euler_road(t: list, v: int = 0):
for i in range(len(t)):
if t[v][i]:
# 删除边
t[v][i], t[i][v] = 0, 0
euler_road(t, i)
# 点入栈
points.append('v' + str(v))
输出:
euler_road(m, 1)
print("欧拉回路为:" + "->".join(points[::-1]))
跟据空格将输入的数字分割开,再将其转化为整数
dushu = list(map(int, input().split()))
3 + 3 + 2 + 2 + 1 = 11 不是2的倍数不是图
第一个数3后面没有3个数,根据Havel定理,不可简单图化
易得该图为两个K2,故可简单图化,但不连通。
根据Havel定理,可简单图化。将图画出后可判断为连通图。其中有奇数度顶点,不是欧拉图。
根据Havel定理,可简单图化。将图画出后可判断为连通图,有欧拉回路:v1->v0->v3->v4->v0->v2->v1
import numpy
import copy
points = []
def judge_graph(l: list) -> bool:
"""
判断是否可图化
:param l: 度数列
:return:
"""
return not sum(l) % 2
def judge_simpleGraph(l: list) -> bool:
"""
判断是否可简单图化
:param l: 度数列
:return:
"""
t = copy.deepcopy(l)
for i in range(len(t)):
t.sort(reverse=True)
# 如果d1为0,则不需要再进行操作
if t[i] == 0:
break
# 判断d1后方是否有d1个数
if i + 1 + t[i] > len(t):
return False
# 对d1后面每一个数减一,如果有负数,则不可简单图化
for j in range(i + 1, i + 1 + t[i]):
t[j] -= 1
if t[j] < 0:
return False
return True
def cal_simple_graph(l: list) -> list:
"""
计算简单图的相邻矩阵
:param l: 度数列
:return: 相邻矩阵
"""
# i用于保存是哪个点,l[i]表示其度数
t = [[i, l[i]] for i in range(len(l))]
# 构建全0相邻矩阵
matrix = [[0] * len(l) for _ in range(len(l))]
for i in range(len(l)):
# 根据度数排序
t.sort(reverse=True, key=lambda x: x[1])
# 对相应的点减少度数,并矩阵对应位置置1
for j in range(i + 1, i + 1 + t[i][1]):
matrix[t[i][0]][t[j][0]] = 1
matrix[t[j][0]][t[i][0]] = 1
t[j][1] -= 1
return matrix
def liantong(l: list) -> bool:
"""
根据相邻矩阵判断是否连通
:param l: 相邻矩阵
:return:
"""
n = copy.deepcopy(l)
# 求邻接矩阵
for i in range(len(n)):
n[i][i] = 1
# 求邻接矩阵的n次幂
t = numpy.array(n)
for _ in range(len(n)):
t = numpy.dot(t, n)
t = list(t)
# 判断结果中是否有非零数
for i in range(len(n)):
for j in range(len(n)):
if t[i][j] == 0:
return False
return True
def euler(l: list) -> bool:
"""
根据相邻矩阵判断是否为欧拉图
:param l: 相邻矩阵
:return:
"""
return not sum([1 for i in l if sum(i) % 2 != 0])
def euler_road(t: list, v: int = 0):
"""
计算欧拉回路
:param t: 相邻矩阵
:param v: 起始点
:return:
"""
for i in range(len(t)):
if t[v][i]:
# 删除边
t[v][i], t[i][v] = 0, 0
euler_road(t, i)
# 点入栈
points.append('v' + str(v))
dushu = list(map(int, input().split()))
if not judge_graph(dushu):
print("非图")
exit()
if judge_simpleGraph(dushu):
print("可简单图化")
m = cal_simple_graph(dushu)
print("相邻矩阵为:")
for i in m:
for j in i:
print(str(j) + " ", end="")
print()
else:
print("不可简单图化")
exit()
if liantong(m):
print("该图连通")
else:
print("该图不连通")
if euler(m):
print("是欧拉图")
euler_road(m, 1)
print("一条欧拉回路为:" + "->".join(points[::-1]))
else:
print("不是欧拉图")
#include "vector"
#include "iostream"
#include "algorithm"
#include "stack"
using namespace std;
stack<int> p;
bool graph(const vector<int> &dushu) {
int sum = 0;
for (int i: dushu) {
sum += i;
}
return !(sum % 2);
}
bool compare(vector<int> x, vector<int> y) {
return x[1] > y[1];
}
bool simple(const vector<int> &t, vector<vector<int>> &m) {
vector<vector<int>> dushu; // [(0,4),(1,2)]
for (int i = 0; i < t.size(); i++) {
vector<int> x;
x.push_back(i);
x.push_back(t[i]);
dushu.push_back(x);
}
for (int i = 0; i < t.size(); i++) {
sort(dushu.begin(), dushu.end(), compare);
if (dushu[i][1] == 0) break;
if (i + 1 + dushu[i][1] > t.size()) return false;
for (int j = i + 1; j < i + 1 + dushu[i][1]; j++) {
dushu[j][1]--;
m[dushu[i][0]][dushu[j][0]] = 1;
m[dushu[j][0]][dushu[i][0]] = 1;
if (dushu[j][1] < 0) return false;
}
}
return true;
}
vector<vector<int>> dot(vector<vector<int>> x, vector<vector<int>> y) {
vector<vector<int>> rep;
for (int i = 0; i < x.size(); ++i) {
vector<int> t;
t.assign(x.size(), 0);
for (int j = 0; j < x.size(); j++) {
for (int k = 0; k < x.size(); ++k) {
t[j] += x[i][k] * y[k][j];
}
}
rep.push_back(t);
}
return rep;
}
bool liantong(vector<vector<int>> m) {
vector<vector<int>> t = m;
for (int i = 0; i < m.size(); i++) {
m[i][i] = 1;
}
for (int i = 0; i < m.size(); i++) {
t = dot(t, m);
}
for (int i = 0; i < m.size(); ++i) {
for (int j = 0; j < m.size(); j++) {
if (t[i][j] == 0) return false;
}
}
return true;
}
bool euler(vector<vector<int>> m) {
for (int i = 0; i < m.size(); ++i) {
int t = 0;
for (int j = 0; j < m.size(); ++j) {
t += m[i][j];
}
if (t % 2 != 0) return false;
}
return true;
}
void euler_road(vector<vector<int>> &t, int v) {
for (int i = 0; i < t.size(); i++) {
if (t[v][i]) {
t[v][i] = 0;
t[i][v] = 0;
euler_road(t, i);
}
}
p.push(v);
}
int main() {
int n;
cout << "请输入点的个数:" << endl;
cin >> n;
vector<int> dushu;
vector<vector<int>> m;
cout << "请输入度数列:" << endl;
for (int i = 0; i < n; i++) {
vector<int> t;
t.assign(n, 0);
m.push_back(t);
int x;
cin >> x;
dushu.push_back(x);
}
if (graph(dushu)) {
if (simple(dushu, m)) {
cout << "可简单图化" << endl << "相邻矩阵为:" << endl;
for (int i = 0; i < m.size(); ++i) {
for (int j = 0; j < m.size(); j++) {
cout << m[i][j] << " ";
}
cout << endl;
}
if (liantong(m)) {
cout << "是连通图" << endl;
if (euler(m)) {
cout << "是欧拉图" << endl;
euler_road(m, 1);
cout << "其中一条欧拉回路为:" << endl;
cout << "v" << p.top();
p.pop();
while (!p.empty()) {
cout << "->" << "v" << p.top();
p.pop();
}
} else {
cout << "不是欧拉图" << endl;
}
} else {
cout << "图不连通" << endl;
}
} else {
cout << "不可简单图化" << endl;
}
} else {
cout << "不可图化" << endl;
}
return 0;
}