离散实验——二元关系及其性质
【实验目的】
掌握二元关系在计算机上的表示方法,并掌握如果判定关系的性质。
【实验内容】
编程判断一个二元关系是否为等价关系,如果是,求其商集。
例:A={1,2,3,4,5,6,7,8,9,10},R={<x,y>|x、y∈A∧y≡x (mod 5)}判断R是否等价关系,如果是,求出各等价类。
A 上满足 关系的有 :
<1,1>,<2,2>,<3,3>,<4,4>,<5,5>,<6,6>,<7,7>,<8,8>,<9,9>,<10,10>,
<1,6>,<2,7>,<3,8>,<4,9>,<5,10>,
<6,1>,<7,2>,<8,3>,<9,4>,<10,5>
【源程序及解析】
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define N 10086 int a[N][N], n; void init() { printf("请输入二元关系的域的个数:"); scanf("%d", &n); printf("请输入关系矩阵。\n"); for (int i = 0; i < n; i++){ for (int j = 0; j < n; j++){ scanf("%d", &a[i][j]); } } } int judge_R(int flag) // 判断是不是 自反关系 { for (int i = 0; i < n&&flag; i++) if (a[i][i] == 0) flag = 0; if (flag) return 1; return 0; } int judge_S(int flag) // 判断是不是 对称关系 { for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (a[i][j] && !a[j][i]) flag = 0; if (flag) return 1; return 0; } int judge_T(int flag) // 判断是不是 传递关系 { for (int i = 0; i < n&&flag; i++) for (int j = 0; j < n&&flag; j++) for (int k = 0; k < n&&flag; k++) if (a[i][j] && a[j][k] && !a[i][k]) flag = 0; if (flag) return 1; return 0; } void show() { int fld[N]; // 二元关系的 域 for (int i = 0; i < n; i++) fld[i] = i + 1; // i 代表第 i 个元素 printf("\n商集为:\n"); printf("{ "); for (int i = 0; i < n; i++) //循环所有元素 { if (fld[i]) // 如果当前元素 所属的等价类 还没打印出来 { printf("{ "); for (int j = 0; j < n; j++) { if (a[i][j] && fld[j]) // 如果与当前元素连通的元素 所属的等价类 还没打印出来 { printf("%d ", fld[j]); fld[j] = 0; // 标记 用过的元素,至于 i,因为不会重复循环,所以不用 标记 } } printf("} "); } } printf("}\n"); } int main(void) { init(); // 初始化矩阵 if (judge_R(1)&&judge_S(1)&&judge_T(1)) // 判断是否是等价关系 // if (judge_R&&judge_S&&judge_T) 怎么这句没报错 show(); // 打印商集 else printf("该二元关系不是等价关系。\n"); system("pause"); return 0; } /*测试数据: 10 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 结果为: 商集为: { { 1 6 } { 2 7 } { 3 8 } { 4 9 } { 5 10 } } */
一,等价关系的判断
1,自反性 (Reflexve) 的判断
若 关系矩阵 主对角线上的元素都是 1,则 R 具有自反性
int judge_R(int flag) // 判断是不是 自反关系 { for (int i = 0; i < n&&flag; i++) if (a[i][i] == 0) flag = 0; if (flag) return 1; return 0; }
2,对称关系 ( Symmetric) 的判断
若 关系矩阵 a [ i] [ j ] == a [ j ] [ i ],则 R 具有对称性
int judge_S(int flag) // 判断是不是 对称关系 { for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (a[i][j] && !a[j][i]) flag = 0; if (flag) return 1; return 0; }
3,传递性(Transitive)的判断
若 关系矩阵 对任意的存在 i 通过 j 到达 k 的路径,都有 i 直接到达 k 的路径,则 R 具有 传递性
即 如果 a[i][j] ==1, a[j][k] ==1,则 a[i][k] ==1
int judge_T(int flag) // 判断是不是 传递关系 { for (int i = 0; i < n&&flag; i++) for (int j = 0; j < n&&flag; j++) for (int k = 0; k < n&&flag; k++) if (a[i][j] && a[j][k] && !a[i][k]) flag = 0; if (flag) return 1; return 0; }
二,商集的求法
void show() { int fld[N]; // 二元关系的 域 for (int i = 0; i < n; i++) fld[i] = i + 1; // i 代表第 i 个元素 printf("\n商集为:\n"); printf("{ "); for (int i = 0; i < n; i++) //循环所有元素 { if (fld[i]) // 如果当前元素 所属的等价类 还没打印出来 { printf("{ "); for (int j = 0; j < n; j++) { if (a[i][j] && fld[j]) // 如果与当前元素连通的元素 所属的等价类 还没打印出来 { printf("%d ", fld[j]); fld[j] = 0; // 标记 用过的元素,至于 i,因为不会重复循环,所以不用 标记 } } printf("} "); } } printf("}\n"); }
商集是由等价类组成的集合,因为所有的等价类都是没有 交集 的,且若 xRy ,则 [x] = [y]
所以我们先循环 二元关系的域,找出与所有与当前元素 连通的 元素,他们就组成了 一个等价类
再把 用过的元素标记一下,就可以不用 当心重复了。
============ ========== ========= ======= ======= ===== ==== === == =
我好像是一个在海边玩耍的孩子,不时为拾到比通常更光滑的石子或更美丽的贝壳而欢欣鼓舞,
而展现在我面前的是完全未探明的真理之海。
—— —— 艾萨克·牛顿