OUC离散数学II实验一实验报告 (Python + Cpp)

实验主题

可简单图化、连通图、欧拉图和哈密顿图的判断

实验目的

1、掌握可简单图化的定义及判断方法;

2、掌握连通图、欧拉图的判断方法;

3、掌握欧拉回路的搜索方法;

4、了解欧拉图的实际应用。

实验要求

1、给定一非负整数序列(例如:(4,2,2,2,2))判断此非负整数序列是否是可图化的,是否是可简单图化的。

2、如果是可简单图化的,根据Havel定理过程求出对应的简单图,并输出此图。

3、判断此简单图是否是连通的。

4、如果是连通图,判断此图是否是欧拉图。如果是欧拉图,请输出一条欧拉回路(输出形式如:v2→v1→v5→v3→v4→v5→v2)。

实验内容

1. 判断是否可图化

根据握手定理,一个图可图化,则图的总度数为偶数

def judge_graph(l: list) -> bool:
    return not sum(l) % 2

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

3. 输出简单图的相邻矩阵

同样根据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()

4. 判断连通图

先根据相邻矩阵求邻接矩阵,对邻接矩阵求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

5. 判断欧拉图

根据欧拉图的充要条件,如果G是欧拉图,则G是连通的,且G中点都为偶数度,只需对相邻矩阵的每一行求和判断其是否为二的倍数即可。

def oular(l: list) -> bool:
    return not sum([1 for i in l if sum(i) % 2 != 0])

6. 搜索欧拉图

确定欧拉图中的一个顶点,选择一个与其关联的点,并删除之间的边,再对选择的这个点执行相同的操作,直到全部的边被删除,再将点入栈,输出的时候再将入栈的点一个个弹出。

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]))

7. 数据输入

跟据空格将输入的数字分割开,再将其转化为整数

dushu = list(map(int, input().split()))

实验测试数据、代码及相关结果分析

(3,3,2,2,1)

3 + 3 + 2 + 2 + 1 = 11 不是2的倍数不是图

OUC离散数学II实验一实验报告 (Python + Cpp)_第1张图片

(3,3,2)

第一个数3后面没有3个数,根据Havel定理,不可简单图化

OUC离散数学II实验一实验报告 (Python + Cpp)_第2张图片

(1,1,1,1)

易得该图为两个K2,故可简单图化,但不连通。

OUC离散数学II实验一实验报告 (Python + Cpp)_第3张图片

(3,2,2,1)

根据Havel定理,可简单图化。将图画出后可判断为连通图。其中有奇数度顶点,不是欧拉图。

OUC离散数学II实验一实验报告 (Python + Cpp)_第4张图片

(4,2,2,2,2)

根据Havel定理,可简单图化。将图画出后可判断为连通图,有欧拉回路:v1->v0->v3->v4->v0->v2->v1

OUC离散数学II实验一实验报告 (Python + Cpp)_第5张图片

实验代码

Python

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("不是欧拉图")

CPP

#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;
}

你可能感兴趣的:(学习,python,c++)