离散数学实验二c语言(输出关系矩阵,输出矩阵性质,输出自反闭包,对称闭包,传递闭包,判断矩阵是否为等价关系,相容关系,偏序关系)

离散数学实验二

一、算法描述,算法思想

(一)相关数据结构
cpp 复制代码
typedef struct Set *S; //存放集合
struct Set
{
    int size; //集合的元素个数
    char *A;   //存放该集合的元素
};

Set存放有限集合A,该集合的元素个数为size,size可以用来判断该集合是否为空集,然后集合中的元素就放在A数组里。

cpp 复制代码
typedef struct Confirm *C; //存放关系的序偶<x, y>
struct Confirm
{
    int x, y;
};

Confirm存放一个序偶<x, y>。

cpp 复制代码
typedef struct Relation *R; //存放关系矩阵
struct Relation
{
    int n, size;   // n行 n列矩阵,序偶个数为size
    int r[10][10]; //关系矩阵
    C c;           //存放该关系的序偶
};

Relation存放集合A的关系,r为一个n行,n列的关系矩阵,size为其中的序偶数,c即存放该关系的所有序偶。

cpp 复制代码
int flagz = 1, flagfz = 1, flagd = 1, flagfd = 1, flagc = 1; // flagz判断是否为自反,flagfz判断是否为反自反,
// flagd判断是否为对称,flagfd判断是否为反对称,flagc判断是否为传递

设置全局变量,方便判断矩阵关系。

(二)相关算法实现
1、输出关系矩阵R
cpp 复制代码
void PrintRelation(R re) //打印关系矩阵
{
    printf("关系矩阵如下:\n");
    for (int i = 0; i < re->n; i++)
    {
        for (int j = 0; j < re->n; j++)
            printf("%d ", re->r[i][j]);
        printf("\n");
    }
    printf("\n");
}

用户输入的为一个关系矩阵,只要将其存储下,然后直接输出即可,注意换行。

2、输出R具有的性质
cpp 复制代码
void PrintCharacter(S s, R re) //判断该矩阵的性质
cpp 复制代码
if (s->size == 0) //空集,关系具有所有性质
    {
        printf("该关系具有以下性质:\n");
        printf("自反性\n");
        printf("反自反性\n");
        printf("对称性\n");
        printf("反对称性\n");
        printf("传递性\n");
        return;
    }

(1)首先是判断该集合是否为空,如果集合为空集,则具有所有的性质。

cpp 复制代码
for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i == j && !re->r[i][j]) //不可能为自反关系
                flagz = 0;
            if (i == j && re->r[i][j]) //不可能为反自反关系
                flagfz = 0;
            if (re->r[i][j] && !re->r[j][i] && i != j) //不可能为对称关系
                flagd = 0;
            if (re->r[i][j] && re->r[j][i] && i != j) //不可能为反对称关系
                flagfd = 0;
        }
    }

(2)确定该集合不为空后,接下来先根据矩阵来判断自反性,反自反性,对称性,反对称性。

如果出现横纵坐标相同的点,但是其不为1,说明该集合存在a属于集合s,但不具有<a, a>序偶,则该矩阵不可能具有自反关系,将flagz = 0;

如果出现横纵坐标相同的点,但是其为1,说明该集合存在a属于该集合,且有<a, a>序偶,则该矩阵不可能具有反自反关系,将flagfz = 0;

如果出现横纵坐标不相同,且相反的两点,但是其为1,说明该集合存在a,b属于该集合,且有<a, b>,<b,a>序偶,则该矩阵不可能具有反对称关系,将flagfd = 0;

如果出现横纵坐标不相同,且相反的两点,但是其只有一个为1,说明该集合存在a,b属于该集合,且有<a, b>,没有<b,a>序偶,则该矩阵不可能具有对称关系,将flagd = 0;

cpp 复制代码
    for (int i = 1; i <= re->size; i++) //判断是否具有传递性
    {
        if (!flagc)
        break;
        int x = re->c[i].x, y = re->c[i].y; //若存在<x, y>
        if (x == y)
            continue;
        for (int j = 0; j < n; j++) //找<y, j>
        {
            if (re->r[y][j] && !re->r[x][j]) //是否存在<x, j>
            {
                flagc = 0;
                break;
            }
        }
    }

(3)接下来是根据矩阵中为1的点,即该集合所具有的序偶来判断是否具有传递关系。

若存在<x, y>,我们去找<y, j>,看是否存在<x, j>,如果不存在则不具有传递关系,flagc = 0。

(4)最后将所有关系输出即可。

3、输出R的自反闭包,对称闭包,传递闭包
cpp 复制代码
void PrintBibao(R re) //计算自反闭包,对称闭包,传递闭包矩阵
cpp 复制代码
    //自反闭包
    int n = re->n;
    R tmp = CopyRelation(re);
    for (int i = 0; i < n; i++)
        tmp->r[i][i] = 1;
    printf("自反闭包矩阵:\n");
    PrintRelation(tmp);
    DestoryRelation(tmp);

(1)计算自反闭包,首先将原矩阵复制到tmp中,将所有横纵坐标相同的点都该为1,即为自反闭包。

cpp 复制代码
    //对称闭包
    tmp = CopyRelation(re);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i != j && tmp->r[i][j])
            {
                tmp->r[j][i] = 1;
            }
        }
    }
    printf("对称闭包矩阵:\n");
    PrintRelation(tmp);
    DestoryRelation(tmp);

(2)计算对称闭包,首先将原矩阵复制到tmp中,将横纵坐标不同的的,原矩阵中存在的为1的点,将其的对称点也改为1,即为对称闭包。

cpp 复制代码
    //传递闭包
    tmp = CopyRelation(re);
    R ans = InitRelationTmp(n);
    AddRelation(ans, re);

    for (int i = 0; i < n-1; i++)
    {
        tmp = Multiply(tmp, re); //最多乘n次
        AddRelation(ans, tmp);
    }
    printf("传递闭包矩阵:\n");
    PrintRelation(ans);
    DestoryRelation(tmp);
    free(ans);

(3)计算传递闭包,首先将原矩阵复制到tmp中,将tmp与原矩阵乘矩阵的行(列)数次,将每次计算的大于1的数改为1,每次将矩阵相加,返回即可。

4、判断R是否为等价关系,相容关系,偏序关系
cpp 复制代码
void PanRelation(R re) //判断矩阵的关系
{
    printf("具有的关系为:\n");
    if (flagz == 1 && flagd == 1 && flagc == 1) //如果为自反,对称,传递则为等价关系
        printf("等价关系\n");
    if (flagz == 1 && flagd == 1) //若为自反,对称则为相容关系
        printf("相容关系\n");
    if (flagz == 1 && flagfd == 1 && flagc == 1) //若为自反,反对称,传递为偏序关系
        printf("偏序关系\n");
}

(1)等价关系:若R具有自反性,对称性,传递性。

(2)相容关系:若R具有自反性,对称性。

(3)偏序关系:若R具有自反性,反对称性,传递性。

(三)流程图

main()函数
void PrintRelation(R re) 打印关系矩阵
void PrintCharacter(S s , R re) 判断该关系矩阵的性质

void PrintBibao(R re) 计算自反闭包,对称闭包,传递闭包矩阵

void PanRelation(R re) 判断矩阵的关系

(四)程序运行截图与样例说明

输入:元素个数、集合的每个元素(用单个字符表示)、该集合的关系矩阵。

输出:关系矩阵、关系矩阵性质、自反闭包、对称闭包、传递闭包矩阵、关系矩阵的关系。

分析:该关系矩阵的序偶为<1,2>,<2,1>,<2,3>,<3,4>。

可以看出该关系矩阵不具有自反性,对称性,反对称性,传递性。

具有反自反性。

且计算的自反闭包,对称闭包,传递闭包与答案相同。

判断的关系也正确。

(五)代码

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
typedef struct Confirm *C; //存放关系的序偶<x, y>
struct Confirm
{
    int x, y;
};
typedef struct Relation *R; //存放关系矩阵
struct Relation
{
    int n, size;   // n行 n列矩阵,序偶个数为size
    int r[10][10]; //关系矩阵
    C c;           //存放该关系的序偶
};
typedef struct Set *S; //存放集合
struct Set
{
    int size; //集合的元素个数
    char *A;   //存放该集合的元素
};
int flagz = 1, flagfz = 1, flagd = 1, flagfd = 1, flagc = 1; // flagz判断是否为自反,flagfz判断是否为反自反,
// flagd判断是否为对称,flagfd判断是否为反对称,flagc判断是否为传递

S InitSet(int size) //创建集合
{
    S s = (S)malloc(sizeof(struct Set));
    s->A = (char *)malloc(sizeof(char) * size);
    s->size = size;

    printf("注意:集合的每个元素用单个字符来表示\n");
    for (int i = 0; i < size; i++)
        scanf("%d", &s->A[i]);
    return s;
}
R InitRelation(int n) //创建关系矩阵
{
    int now = 0;
    R re = (R)malloc(sizeof(struct Relation));
    re->n = n;
    re->c = (C)malloc(sizeof(struct Confirm) * n);
    
    printf("请输入该集合的关系矩阵(n*n):\n");
    for (int i = 0; i < re->n; i++)
    {
        for (int j = 0; j < re->n; j++)
        {
            scanf("%d", &re->r[i][j]);
            if (re->r[i][j])
            {
                re->c[++now].x = i;
                re->c[now].y = j;
            }
        }
    }
    re->size = now;
    return re;
}
R InitRelationTmp(int n)
{
    R tmp = (R)malloc(sizeof(struct Relation));
    tmp->n = n;
    for (int i=0; i<tmp->n; i++)
    {
        for (int j=0; j<tmp->n; j++)
        tmp->r[i][j] = 0;
    }
    return tmp;
}

void DestorySet(S s) //释放集合内存
{
    free(s->A);
    free(s);
}
void DestoryRelation(R re) //释放关系矩阵内存
{
    free(re->c);
    free(re);
}

void PrintRelation(R re) //打印关系矩阵
{
    printf("关系矩阵如下:\n");
    for (int i = 0; i < re->n; i++)
    {
        for (int j = 0; j < re->n; j++)
            printf("%d ", re->r[i][j]);
        printf("\n");
    }
    printf("\n");
}
R Multiply(R re, R re2) //计算两矩阵相乘,且将相乘后的大于1的数改为1
{
    int n = re->n, tmp = 0, i, j;
    R ans = InitRelationTmp(n);
    for (i = 0; i < n; i++) //每一行
    {
        for (j = 0; j < n; j++) //该行的列
        {
            tmp = 0;
            for (int k = 0; k < n; k++)
            {
                tmp += re->r[i][k] * re2->r[k][j];
            }
            if (tmp >= 1)
                {
                    ans->r[i][j] = 1;
                }
        }
    }
    return ans; //返回得出的矩阵
}
void AddRelation(R re1, R re2)
{
    int n = re1->n;
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
        {
            re1->r[i][j] += re2->r[i][j];
            if (re1->r[i][j]>1)
            re1->r[i][j] = 1;
        }
    }
}

void PrintCharacter(S s, R re) //判断该矩阵的性质
{
    int n = re->n;
    if (s->size == 0) //空集,关系具有所有性质
    {
        printf("该关系具有以下性质:\n");
        printf("自反性\n");
        printf("反自反性\n");
        printf("对称性\n");
        printf("反对称性\n");
        printf("传递性\n");
        return;
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i == j && !re->r[i][j]) //不可能为自反关系
                flagz = 0;
            if (i == j && re->r[i][j]) //不可能为反自反关系
                flagfz = 0;
            if (re->r[i][j] && !re->r[j][i] && i != j) //不可能为对称关系
                flagd = 0;
            if (re->r[i][j] && re->r[j][i] && i != j) //不可能为反对称关系
                flagfd = 0;
        }
    }
    for (int i = 1; i <= re->size; i++) //判断是否具有传递性
    {
        if (!flagc)
        break;
        int x = re->c[i].x, y = re->c[i].y; //若存在<x, y>
        if (x == y)
            continue;
        for (int j = 0; j < n; j++) //找<y, j>
        {
            if (re->r[y][j] && !re->r[x][j]) //是否存在<x, j>
            {
                flagc = 0;
                break;
            }
        }
    }
    //输出性质
    printf("该关系具有以下性质:\n");
    if (flagz == 1)
        printf("自反性\n");

    if (flagfz == 1)
        printf("反自反性\n");

    if (flagd == 1)
        printf("对称性\n");

    if (flagfd == 1)
        printf("反对称性\n");

    if (flagc == 1)
        printf("传递性\n");

    if (!flagz&&!flagfz&&!flagd&&!flagfd&&!flagc)
    printf("该关系矩阵不具有自反、反自反、对称、反对称、传递性\n");
}
R CopyRelation(R re) //复制关系矩阵,方便计算
{
    R tmp = (R)malloc(sizeof(struct Relation));
    tmp->n = re->n;
    tmp->size = re->size;
    tmp->c = (C)malloc(sizeof(struct Confirm) * tmp->size);
    for (int i = 0; i < tmp->n; i++)
    {
        for (int j = 0; j < tmp->n; j++)
            tmp->r[i][j] = re->r[i][j];
    }
    for (int i = 1; i <= tmp->size; i++)
    {
        tmp->c[i].x = re->c[i].x;
        tmp->c[i].y = re->c[i].y;
    }
    return tmp; //返回该复制的矩阵
}
void PrintBibao(R re) //计算自反闭包,对称闭包,传递闭包矩阵
{
    //自反闭包
    int n = re->n;
    R tmp = CopyRelation(re);
    for (int i = 0; i < n; i++)
        tmp->r[i][i] = 1;
    printf("自反闭包矩阵:\n");
    PrintRelation(tmp);
    DestoryRelation(tmp);

    //对称闭包
    tmp = CopyRelation(re);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i != j && tmp->r[i][j])
            {
                tmp->r[j][i] = 1;
            }
        }
    }
    printf("对称闭包矩阵:\n");
    PrintRelation(tmp);
    DestoryRelation(tmp);

    //传递闭包
    tmp = CopyRelation(re);
    R ans = InitRelationTmp(n);
    AddRelation(ans, re);

    for (int i = 0; i < n-1; i++)
    {
        tmp = Multiply(tmp, re); //最多乘n次
        AddRelation(ans, tmp);
    }
    printf("传递闭包矩阵:\n");
    PrintRelation(ans);
    DestoryRelation(tmp);
    free(ans);
}
void PanRelation(R re) //判断矩阵的关系
{
    int flag = 0;
    printf("具有的关系为:\n");
    if (flagz == 1 && flagd == 1 && flagc == 1) //如果为自反,对称,传递则为等价关系
    {
        printf("等价关系\n");
        flag = 1;
    }
    if (flagz == 1 && flagd == 1) //若为自反,对称则为相容关系
    {
        printf("相容关系\n");
        flag = 1;
    }
    if (flagz == 1 && flagfd == 1 && flagc == 1) //若为自反,反对称,传递为偏序关系
    {
        printf("偏序关系\n");
        flag = 1;
    }
    if (!flag)
    printf("该关系矩阵不具有等价、相容、偏序关系\n");
}

int main()
{
    int size;
    printf("请输入该集合的元素个数:\n");
    scanf("%d", &size);

    S s = InitSet(size);       //输入集合
    R re = InitRelation(size); //输入关系矩阵

    PrintRelation(re);     //打印关系矩阵
    PrintCharacter(s, re); //打印矩阵性质
    PrintBibao(re);        //打印闭包矩阵
    PanRelation(re);       //判断矩阵的关系

    DestorySet(s); //释放内存
    DestoryRelation(re);

    return 0;
}
相关推荐
古希腊掌管学习的神几秒前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
云边有个稻草人4 分钟前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
半盏茶香5 分钟前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
忘梓.1 小时前
解锁动态规划的奥秘:从零到精通的创新思维解析(3)
算法·动态规划
字节高级特工1 小时前
【C++】深入剖析默认成员函数3:拷贝构造函数
c语言·c++
计算机学长大白2 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
tinker在coding3 小时前
Coding Caprice - Linked-List 1
算法·leetcode
XH华7 小时前
初识C语言之二维数组(下)
c语言·算法
南宫生8 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_8 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯