离散数学 实验报告-1

1. 实验目的

熟悉关系的性质,掌握求判断关系性质的方法。

2. 实验内容

本实验要求从键盘输入一个关系的关系矩阵,判断该关系是否是自反的、对称的、传递的、反自反的、反对称的。用 C 语言或 MATLAB 实现。

  • 定义 1:设 $R$ 是集合 $X$ 上的二元关系,对任意的 $x \in X$,都满足 $\langle x,x \rangle \in R$,则 $R$ 是自反的
  • 定义 2:设 $R$ 是集合 $X$ 上的二元关系,对任意的 $x \in X$,都满足 $\langle x,x \rangle \notin R$,则 $R$ 是反自反的
  • 定义 3:设 $R$ 是集合 $X$ 上的二元关系,对任意的 $x,y \in X$,满足 $\langle x,y \rangle \in R \Rightarrow \langle y,x \rangle \in R$,则 $R$ 是对称的
  • 定义 4:设 $R$ 是集合 $X$ 上的二元关系,对任意的 $x,y \in X$,满足 $\langle x,y \rangle \in R \land \langle y,x \rangle \in R \Rightarrow x=y$,则 $R$ 是反对称的
  • 定义 5:设 $R$ 是集合 $X$ 上的二元关系,对任意的 $x,y,z \in X$,满足 $\langle x,y \rangle \in R \land \langle y,z \rangle \in R \Rightarrow \langle x,z \rangle \in R$,则 $R$ 是传递的

3. 程序清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LINE_BUF 512 // 单行输入缓冲大小

/**
* @brief 从一行文本中读取并校验 n 个 0/1 元素到 row 数组
*
* @param n 元素数量
* @param row 数组指针
* @return int X->读取元素个数 | -1->输入结束
*/
static int read_row(int n, int *row)
{
char buf[LINE_BUF];

if (fgets(buf, LINE_BUF, stdin) == NULL) {
// 输入已结束
return -1;
}

int cnt = 0;
char *tok = strtok(buf, " \t\r\n");
while (tok != NULL) {
// 一行中的元素个数超过 n 时按输入有误处理, 避免越界写入
if (cnt >= n) {
return n + 1;
}

char *end = NULL;
long v = strtol(tok, &end, 10);
// 只接受整数, 且取值只能是 0 或 1
if (end == tok || *end != '\0' || (v != 0 && v != 1)) {
return cnt;
}

row[cnt++] = (int)v;
tok = strtok(NULL, " \t\r\n");
}
return cnt;
}

/**
* @brief 从键盘获取 n 阶 0/1 关系矩阵的函数, 按行输入
*
* @param n 矩阵阶数
* @return int** 矩阵二阶数组指针
*/
int **get_matrix(int n)
{
// 为指针数组(每行首地址)分配内存
int **matrix = (int **)malloc(n * sizeof(int *));
if (matrix == NULL) {
printf("Failed to allocate array memory.\r\n");
exit(1);
}

for (int i = 0; i < n; i++) {
// 为每一行元素分配内存
matrix[i] = (int *)malloc(n * sizeof(int));
if (matrix[i] == NULL) {
printf("Failed to allocate elements memory.\r\n");
// 释放已分配的各行及指针数组后再退出
for (int j = 0; j < i; j++) {
free(matrix[j]);
}
free(matrix);
exit(1);
}
}

// 逐行输入并校验, 直到每行都合法
for (int i = 0; i < n; i++) {
while (1) {
int cnt = read_row(n, matrix[i]);
if (cnt == n) {
// 本行读取成功
break;
}
if (cnt == -1) {
printf("Illegal input!\r\n");
exit(1);
}
printf("第 %d 行输入有误,应为 %d 个 0 或 1,请重新输入:\r\n", i + 1, n);
}
}
return matrix;
}

/**
* @brief 判断关系矩阵是否具有自反性
*
* @param n 矩阵阶数
* @param matrix 矩阵二阶数组指针
* @return int 1->有 | 0->无
*/
int reflexivity(int n, int **matrix)
{
for (int i = 0; i < n; i++) {
if (matrix[i][i] != 1) return 0;
}
return 1;
}

/**
* @brief 判断关系矩阵是否具有反自反性
*
* @param n 矩阵阶数
* @param matrix 矩阵二阶数组指针
* @return int 1->有 | 0->无
*/
int anti_reflexivity(int n, int **matrix)
{
for (int i = 0; i < n; i++) {
if (matrix[i][i] != 0) return 0;
}
return 1;
}

/**
* @brief 判断关系矩阵是否对称
*
* @param n 矩阵阶数
* @param matrix 矩阵二阶数组指针
* @return int 1->有 | 0->无
*/
int symmetry(int n, int **matrix)
{
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (matrix[i][j] != matrix[j][i]) return 0;
}
}
return 1;
}

/**
* @brief 判断关系矩阵是否反对称
*
* @param n 矩阵阶数
* @param matrix 矩阵二阶数组指针
* @return int 1->有 | 0->无
*/
int anti_symmetry(int n, int **matrix)
{
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (matrix[i][j] == 1 && matrix[j][i] == 1) return 0;
}
}
return 1;
}

/**
* @brief 判断关系矩阵是否具有传递性
*
* @param n 矩阵阶数
* @param matrix 矩阵二阶数组指针
* @return int 1->有 | 0->无
*/
int transitivity(int n, int **matrix)
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 1) {
for (int p = 0; p < n; p++) {
if (matrix[j][p] == 1) {
if (matrix[i][p] != 1) return 0;
}
}
}
}
}
return 1;
}

int main(void)
{
int n = 0;
printf("请输入矩阵的阶数 n:");
if (scanf("%d", &n) != 1) {
printf("阶数输入错误!\r\n");
return 1;
}

if (n <= 0 || n > 100) {
printf("阶数 n 应为 1 ~ 100 之间的整数!\r\n");
return 1;
}

// 吃掉阶数后的换行符, 避免残留影响后续逐行读取
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {}

// 逐行输入 0/1 关系矩阵
printf("请按行输入矩阵,使用空格分隔:\r\n");
int **matrix = get_matrix(n);

if (reflexivity(n, matrix)) printf("关系矩阵具有自反性\r\n");
if (anti_reflexivity(n, matrix)) printf("关系矩阵具有反自反性\r\n");
if (symmetry(n, matrix)) printf("关系矩阵具有对称性\r\n");
if (anti_symmetry(n, matrix)) printf("关系矩阵具有反对称性\r\n");
if (transitivity(n, matrix)) printf("关系矩阵具有传递性\r\n");

// 释放内存
for (int i = 0; i < n; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}

4. 调试步骤

  1. 输入测试数据:
1
2
3
4
5
请输入矩阵的阶数 n:3
请按行输入矩阵,使用空格分隔:
1 0 0
0 1 0
0 0 1
  1. 程序输出:
1
2
3
4
关系矩阵具有自反性
关系矩阵具有对称性
关系矩阵具有反对称性
关系矩阵具有传递性

5. 分析与思考

在写判断关系矩阵性质的函数时,一定要根据书上的定义去写判断条件。只要判断条件写对了,判断函数就不会有太大的问题。


离散数学 实验报告-1
https://flowerdown.org/posts/20230511-201429
作者
Unrealfeathers
发布于
2023年5月11日
许可协议