#include<iostream>
#include<stdio.h>
#include<ctime>
using namespace std;
class Euler
{
public:
Euler(int num);
~Euler();
void DFS(int begin);//公有的深度优先搜索函数
void inputEdge(int m);//输入边
void PrintAM();//打印邻接矩阵
void PrintRM();//打印可达性矩阵
void Warshall();//Warshall算法求可达性矩阵
bool IsConnected();//判断图是否连通
int IsEorSE();//判断图是欧拉图还是半欧拉图
bool isEuler;
private:
void DFS(int u, int v, bool **visited);//私有的深度优先搜索函数
int n;
int **a;//定义动态二维数组
int **p;
int *b;//存储每个结点的度数
};
Euler::Euler(int num)//构造函数
{
isEuler = false;
n = num;
int i, j;
a = new int*[n];
for (i = 0; i < n; i++)
{
a[i] = new int[n];
for (j = 0; j < n; j++)
a[i][j] = 0;
}
p = new int*[n];
for (i = 0; i < n; i++)
{
p[i] = new int[n];
for (j = 0; j < n; j++)
p[i][j] = 0;
}
b = new int[n];
for(i = 0; i < n; i++)
b[i] = 0;
}
Euler::~Euler()//析构函数
{
int i;
for (i = 0; i < n; i++)
delete[]a[i];
delete[]a;
for (i = 0; i < n; i++)
delete[]p[i];
delete[]p;
delete[]b;
}
void Euler::inputEdge(int m) //输入边
{
int i, c, d;
cout << "输入存在边<a,b>,结点序号为0-" << n - 1 << endl;
for (i = 0; i < m; i++)
{
cin >> c >> d;
while (c < 0 || c >= n || d < 0 || d >= n)//检查输入是否正确
{
cout << "输入有误,请重新输入边:";
cin >> c >> d;
}
a[c][d] = 1; a[d][c] = 1;
p[c][d] = 1; p[d][c] = 1;
}
}
void Euler::PrintAM()//打印邻接矩阵
{
cout << "输出邻接矩阵a:" << endl;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
cout << a[i][j] << " ";
cout << endl;
}
}
void Euler::Warshall()//Warshall算法求可达性矩阵
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (p[j][i] == 1)
{
for (int k = 0; k < n; k++)
{
if (p[j][k] + p[i][k] > 0)
p[j][k] = 1;
}
}
}
void Euler::PrintRM()//打印可达性矩阵
{
cout << "输出可达性矩阵:" << endl;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
cout << p[i][j] << " ";
cout << endl;
}
}
bool Euler::IsConnected()//判断图是否连通
{
int i, j;
bool flag = true;//flag标记是否连通
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
if (p[i][j] == 0)//如果可达性矩阵中有一个元素为0,
{ //就跳出循环,表示该图不连通
flag = false;
break;
}
if (!flag)
break;
}
if (!flag)
cout << "该图不是连通的";
else
{
for (i = 0; i < n; i++)
for (j = i; j < n; j++)
{
if (a[i][j] == 1 && i != j)//由边计算结点的度数
{
b[i]++; b[j]++;
}
}
}
return flag;
}
int Euler::IsEorSE()//判断图是欧拉图还是半欧拉图
{
int i, count = 0, begin = -1;
cout << "每个结点的度数:" << endl;
for (i = 0; i < n; i++)
cout << i << ":" << b[i] << endl;
for (i = 0; i < n; i++)//计算奇数结点的个数
if (b[i] % 2 != 0)
{
count++;
begin = i;//初始化开始结点,存在奇数结点,则将其中一个作为开始点
}
if (begin == -1)//不存在奇数结点则将0作为起始点
begin = 0;
if (count == 2)
{
cout << "该图是半欧拉图" << endl; isEuler = true;//isEuler标记是否是(半)欧拉图
}
else if (count == 0)
{
cout << "该图是欧拉图" << endl; isEuler = true;
}
return begin;
}
void Euler::DFS(int begin)//公有的深度优先搜索函数
{
int i, j;
bool **visited = new bool*[n];//二维数组记录每条边是否被访问过
for (i = 0; i < n; i++)//初始化
{
visited[i] = new bool[n];
for (j = 0; j < n; j++)
if (a[i][j] == 1)
visited[i][j] = false;
else
visited[i][j] = true;
}
for (j = 0; j < n; j++)
if (!visited[begin][j])
{
DFS(begin, j, visited);
cout << begin << " ";
}
for (i = 0; i < n; i++) delete[]visited[i];//释放内存
delete[]visited;
}
void Euler::DFS(int u, int v, bool **visited) {
if (!visited[u][v])//判断边<u,v>是否访问过
{
visited[u][v] = true; visited[v][u] = true;//标记被访问
for (int i = 0; i < n; i++)
DFS(v, i, visited);
cout << v << " "; //输出结点
}
}
int main()
{
int n, m, begin;
bool flag;
cout << "输入结点个数:";
cin >> n;
Euler euler(n);
cout << "输入边数:";
cin >> m;
euler.inputEdge(m);
euler.PrintAM();
euler.Warshall();
euler.PrintRM();
flag = euler.IsConnected();
if (flag)
{
begin = euler.IsEorSE();
if (euler.isEuler)
{
cout << "具体路径为:"; euler.DFS(begin);
}
}
cout << endl;
return 0;
}
大二(上)离散数学 欧拉图的判定
最新推荐文章于 2023-06-17 22:37:43 发布