文章目录
一、 实验目的和要求
中文五号宋体,英文五号Times new roman字体,1.25倍行距
描述本次实验的目的和要求。
二、实验环境(实验设备)
中文五号宋体,英文五号Times new roman字体,1.25倍行距
硬件:微型计算机
软件:Windows 操作系统、Microsoft Visual C++6.0、Java等可视化编程语言
三、实验原理及内容
中文五号宋体,英文五号Times new roman字体,1.25倍行距
说明:这部分内容主要包括:
1、形式化描述实验中所使用的数据结构和存储结构,给出函数之间的调用关系和数据传递方式;
2、给出核心算法的C++或Java等语言的源代码,并加上详细注释,分析算法的时间复杂度;
3、给出测试数据及运行结果、实验相关结论等。
(一)数据结构和存储结构:主要是数组
EXP4 e = new EXP4(100); // 可达矩阵的最大节点数来构造
rand(); // 随机生成
printConnectedMatrix(); //打印邻接矩阵
getReachableMatrix(); //获取可达矩阵
unitization(); // 可达矩阵单位化
printReachableMatrix(); //打印可达矩阵
isReachable();
getDegrees(); //获取所有节点的度数
printEulerMap();
依次执行
(二)核心算法
public void getEulerMap(int currentIndex) { // 传入参数为当前的欧拉路节点次序
if (has == 1) return;
if (count == edge + 1) {
print(); // 打印欧拉路的节点
has = 1;
}
else {
for (int i = 0; i < n; i++) {
if (connectedMatrix[currentIndex][i] == 1 && vis[currentIndex][i] == 0) {
vis[i][currentIndex] = vis[currentIndex][i] = 1;
node[count++] = i;
getEulerMap(i);
count--;
vis[i][currentIndex] = vis[currentIndex][i] = 0;
}
}
}
}
递归法求欧拉路
时间复杂度为O( n ^ 2)
(三)测试数据及运行结果
测试一:
- num of node is: 6
- ConnectedMatrix
- 0 1 0 0 0 0
- 1 0 0 0 0 1
- 0 0 0 0 1 0
- 0 0 0 0 0 0
- 0 0 1 0 0 1
- 0 1 0 0 1 0
- ReachableMatrix
- 1 1 1 0 1 1
- 1 1 1 0 1 1
- 1 1 1 0 1 1
- 0 0 0 0 0 0
- 1 1 1 0 1 1
- 1 1 1 0 1 1
- isReachable? false
- Neither Euler road nor Euler circuit
测试二:
- num of node is: 7
- ConnectedMatrix
- 0 1 1 0 0 1 1
- 1 0 0 0 0 1 0
- 1 0 0 1 1 1 1
- 0 0 1 0 1 0 1
- 0 0 1 1 0 0 0
- 1 1 1 0 0 0 1
- 1 0 1 1 0 1 0
- ReachableMatrix
- 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1
- isReachable? true
- Euler road
- 2->0->1->5->0->6->2->3->4->2->5->6->3
测试三:
- num of node is: 5
- ConnectedMatrix
- 0 0 0 1 1
- 0 0 1 1 1
- 0 1 0 0 1
- 1 1 0 0 0
- 1 1 1 0 0
- ReachableMatrix
- 1 1 1 1 1
- 1 1 1 1 1
- 1 1 1 1 1
- 1 1 1 1 1
- 1 1 1 1 1
- isReachable? true
- Euler road
- 1->2->4->0->3->1->4
测试四:
- num of node is: 8
- ConnectedMatrix
- 0 0 0 0 0 1 1 1
- 0 0 0 0 1 0 0 0
- 0 0 0 0 0 0 0 1
- 0 0 0 0 1 1 0 1
- 0 1 0 1 0 1 1 0
- 1 0 0 1 1 0 1 1
- 1 0 0 0 1 1 0 1
- 1 0 1 1 0 1 1 0
- ReachableMatrix
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1
- isReachable? true
- Neither Euler road nor Euler circuit
测试五:
- num of node is: 5
- ConnectedMatrix
- 0 1 1 1 1
- 1 0 1 1 1
- 1 1 0 1 1
- 1 1 1 0 1
- 1 1 1 1 0
- ReachableMatrix
- 1 1 1 1 1
- 1 1 1 1 1
- 1 1 1 1 1
- 1 1 1 1 1
- 1 1 1 1 1
- isReachable? true
- Euler circuit
- 0->1->2->0->3->1->4->2->3->4->0
测试六:
- num of node is: 10
- ConnectedMatrix
- 0 1 1 1 1 1 1 1 1 1
- 1 0 1 1 1 1 1 1 0 1
- 1 1 0 1 1 1 1 1 1 1
- 1 1 1 0 1 1 1 1 1 1
- 1 1 1 1 0 1 1 1 1 1
- 1 1 1 1 1 0 1 1 1 1
- 1 1 1 1 1 1 0 1 1 1
- 1 1 1 1 1 1 1 0 1 1
- 1 0 1 1 1 1 1 1 0 1
- 1 1 1 1 1 1 1 1 1 0
- ReachableMatrix
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1
- isReachable? true
- Neither Euler road nor Euler circuit
四、实验小结(包括问题和解决方法、心得体会、意见与建议等)
中文五号宋体,英文五号Times new roman字体,1.25倍行距
说明:这部分内容主要包括:在编程、调试或测试过程中遇到的问题及解决方法、本次实验的心得体会、进一步改进的设想等。
(一)实验中遇到的主要问题及解决方法
- 在利用函数isEulerMap()判断是否是孤立节点时,发现单个节点的图经函数判断后是EulerMap,改正后,即将孤立节点考虑后,函数功能正确。
- 在编写如何求路径的时候,查找了多种算法说明,最终选择一种进行代码实现。
(二)实验心得
对如何利用计算机求欧拉图有了深刻的认识,对离散数学中的相关图论的概念有了更深的理解。
(三)意见与建议(没有可省略)
五、全部源代码(Java)
(一)(半)欧拉图的判定,求欧拉(回)路
import java.lang.Math;
import java.util.Random;
public class EXP4 {
private int[][] graph; // 随机生成的原始矩阵
private int[][] connectedMatrix; // 邻接矩阵
private int[][] reachableMatrix; // 可达矩阵
private int[] degrees; // 度数数组
private int n; // 总节点数
private int edge; // 边
private int sumDegrees; // 总节点数
private int has; // 标志符
private int[][] vis; // 临时数组
private int[] node; // 存放欧拉路的节点的数组
private int count; // 已找到的欧拉路的节点个数
// 构造函数
public EXP4(int size) {
this.graph = new int[size][size];
this.connectedMatrix = new int[size][size];
this.reachableMatrix = new int[size][size];
this.degrees = new int[size];
this.vis = new int[size][size];
this.node = new int[size];
}
// 随机生成邻接矩阵
public void rand() {
// 随机数生成器
Random rand = new Random();
// 随机生成 10 个以内的节点
n = rand.nextInt(10) + 1;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// 控制产生 1 和 0 的概率 为 1:1
graph[i][j] = Math.random() > 0.5 ? 0 : 1;
graph[j][i] = graph[i][j];
if (i == j) {
graph[i][j] = 0;
}
}
}
connectedMatrix = graph;
System.out.println("num of node is: " + n);
System.out.println();
}
// 矩阵加法
public int[][] addition(int[][] m1, int[][] m2) {
int[][] tmp = new int[100][100];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
tmp[i][j] = m1[i][j] + m2[i][j];
}
}
return tmp;
}
// 矩阵乘法
public int[][] multiplication(int[][] m1, int[][] m2) {
int[][] tmp = new int[100][100];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
tmp[i][j] += m1[i][k] * m2[k][j];
}
}
}
return tmp;
}
// 求可达矩阵
public void getReachableMatrix() {
reachableMatrix = graph;
for (int i = 0; i < n - 1; i++) {
graph = multiplication(graph, connectedMatrix); // 求矩阵的幂
reachableMatrix = addition(graph, reachableMatrix); // 求矩阵幂的和
}
}
// 判断是否是可达
public boolean isReachable() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) { // 如果有为零的,返回 false
if (reachableMatrix[i][j] == 0) {
return false;
}
}
}
return true;
}
// 可达矩阵单位化
public void unitization() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (reachableMatrix[i][j] != 0) {
reachableMatrix[i][j] = 1;
}
}
}
}
// 是否是(半)欧拉图
public int isEulerMap() {
// 如果是孤立节点返回 0
if (n == 0) {
return 0;
}
// 记录奇数的节点的个数
int num = 0;
// 如果不可达 返回 0
if (isReachable() == false) {
return 0;
}
// 计算度数为奇数的节点的个数
for (int i = 0; i < n; i++) {
if (degrees[i] % 2 == 1) {
num++;
}
}
// 如果度数为奇数的节点的个数为 0, 返回 1 (半欧拉图)
if (num == 2) {
return 1;
}
// 如果度数为奇数的节点的个数为 0, 返回 2 (欧拉图)
if (num == 0) {
return 2;
}
System.out.println();
// 其他情况, 返回 0
return 0;
}
// 计算所有节点的度数
public void getDegrees() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (connectedMatrix[i][j] != 0) {
degrees[i]++;
}
}
}
for (int i = 0; i < n; i++) {
sumDegrees += degrees[i];
}
// 利用度数之和等于边数的二倍求边数
edge = sumDegrees / 2;
}
// 打印各个节点的度数
public void printDegrees() {
for (int i = 0; i < n; i++) {
System.out.print(degrees[i] + " ");
}
}
// 打印可达矩阵
public void printReachableMatrix() {
System.out.println("ReachableMatrix");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(reachableMatrix[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
// 打印邻接矩阵
public void printConnectedMatrix() {
System.out.println("ConnectedMatrix");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(connectedMatrix[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
// 欧拉路计算(核心算法)
public void getEulerMap(int currentIndex) {
if (has == 1) return;
if (count == edge + 1) {
for (int i = 0; i < count; i++) {
if (i == 0) {
System.out.print(node[i]);
} else {
System.out.print("->" + node[i]);
}
}
System.out.println();
has = 1;
} else {
for (int i = 0; i < n; i++) {
if (connectedMatrix[currentIndex][i] == 1 && vis[currentIndex][i] == 0) {
vis[i][currentIndex] = vis[currentIndex][i] = 1;
node[count++] = i;
getEulerMap(i);
count--;
vis[i][currentIndex] = vis[currentIndex][i] = 0;
}
}
}
}
// 打印欧拉路
public void printEulerMap() {
int result = isEulerMap();
if (result == 1) {
System.out.println("Euler road");
for (int i = 0; i < n; i++) {
int t = 0;
for (int j = 0; j < n; j++) {
if (connectedMatrix[i][j] == 1) {
t++;
}
}
if (t % 2 == 1) {
node[count++] = i;
getEulerMap(i);
count--;
break;
}
}
return;
} else if (result == 2) {
System.out.println("Euler circuit");
node[count++] = 0;
getEulerMap(0); //找出回路
count--;
} else {
System.out.println("Neither Euler road nor Euler circuit");
}
}
// 主函数
public static void main(String[] args) {
EXP4 e = new EXP4(100); // 可达矩阵的最大节点数来构造
e.rand(); // 随机生成
e.printConnectedMatrix(); //打印邻接矩阵
e.getReachableMatrix(); //获取可达矩阵
e.unitization(); // 可达矩阵单位化
e.printReachableMatrix(); //打印可达矩阵
System.out.println("isReachable? " + e.isReachable());
e.getDegrees(); //获取所有节点的度数
e.printEulerMap(); //打印欧拉路
}
}