【实验目的】掌握求关系闭包的方法。

【实验内容】编程求一个关系的闭包,要求传递闭包用warshall方法。

例 :A={8、6、4、2},A上的关系R={<8,6><6,8><6,4><4,2>}

结果:

自反闭包:
{ <8,8>,<8,6>,<6,8>,<6,6>,<6,4>,<4,4>,<4,2>,<2,2> }
1 1 0 0
1 1 1 0
0 0 1 1
0 0 0 1
对称闭包:
{ <8,6>,<6,8>,<6,4>,<4,6>,<4,2>,<2,4> }
0 1 0 0
1 0 1 0
0 1 0 1
0 0 1 0
传递闭包:
{ <8,8>,<8,6>,<8,4>,<8,2>,<6,8>,<6,6>,<6,4>,<6,2>,<4,2> }
1 1 1 1
1 1 1 1
0 0 0 1
0 0 0 0

【源程序及解析】

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 100
int n;   // 
int r[N][N];  // 关系矩阵
int c[N][N];  // 可以初始化为关系矩阵, 最后用来存放 闭包矩阵
int set[N];   // 存放 集合中的元素
void initc(int t[][N])  // 将 闭包矩阵 化成  其他的矩阵
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            c[i][j] = t[i][j];
}
void show()
{
    int flag = 0;
    printf("{ ");
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
        {
            if (c[i][j])  // 这个 三目运算 用的挺秀的
            {
                printf(flag ? ",<%d,%d>" : "<%d,%d>", set[i], set[j]);
                flag = 1;
            }
        }
    printf(" }\n");
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
            printf("%d ", c[i][j]);
        puts("");
    }
}
void funR()   // 求 自反闭包
{
    initc(r);
    for (int i = 0; i < n; i++)
        c[i][i] = 1;
    printf("自反闭包:\n");
    show();
}
void funS()  // 求 对称闭包
{
    initc(r);
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (c[i][j])
                c[j][i] = 1;
        }
    }
    printf("对称闭包:\n");
    show();
}
void funT1(void)  // 求 传递闭包第一种方法
{
    initc(r);
    int b[N][N];
    for (int m = 1; m < n; m++)  // 求 矩阵的 n-1 次方
    {
        for (int i = 0; i < n; i++)  
        {
            for (int j = 0; j < n; j++)
            {
                b[i][j] = 0;
                for (int k = 0; k < n; k++)
                    b[i][j] += c[i][k] * r[k][j];  // 矩阵运算

                c[i][j] += b[i][j];   // 将求得的 矩阵的 m 次方与前面的累 并
                if (c[i][j])
                    c[i][j] = 1;
            }
        }
    }
    printf("传递闭包:\n");
    show();
}
void funT2(void)   // 求 传递闭包第二种方法
{
    initc(r);
    for (int k = 0; k < N; k++)   // 枚举途径 某中间顶点 k 的任两个顶点对 i 和 j ,进而通过判断 k->j 是否连接,来判断 是否将 i->j 连接
    {
        for (int i = 0; i < N; i++)
            if (c[i][k])
                for (int j = 0; j < N; j++)
                {
                    /* 有两种情况  
                       ①,若 i->j 已连接,则 k->j 是否连接 并无影响
                       ②  若 i->j 没有连接,则 k->j 连接了,则将 i->j 连接
                                           则 k->j 没有连接,则不必将 i->j 连接      
                    */  
                    c[i][j] = c[i][j] + c[k][j];   
                    if (c[i][j])
                        c[i][j] = 1;
                }
    }
    printf("传递闭包:\n");
    show();
}
int main(void)
{
    printf("请输入集合的元素个数:");
    scanf("%d", &n);
    printf("请输入集合内容:\n");
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &set[i]);
    }

    printf("请输入二元关系的序偶个数:");
    int lon; scanf("%d", &lon);
    printf("请输入集合上的二元关系:\n");
    for (int i = 0; i < lon; i++)
    {
        char s1, s2;
        int a, b; scanf(" %c%d,%d %c", &s1, &a, &b, &s2);
        for (int i = 0; i < n; i++)    // 将有序对第一元素 变成 邻接矩阵的横坐标
            if (set[i] == a)
            {
                a = i;
                break;
            }
        for (int i = 0; i < n; i++)   // 将有序对第二元素 变成 邻接矩阵的纵坐标
            if (set[i] == b)
            {
                b = i;
                break;
            }
        r[a][b] = 1;
    }
    puts("");
    funR();
    funS();
    funT1();
    funT2();

    system("pause");
    return 0;
}
/*
测试数据 1:
4
8 6 4 2
4
<8,6> <6,8> <6,4> <4,2>
测试数据 2:
3
1 2 3
3
<1,2> <2,3> <3,1>

*/
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-08-02
  • 2022-12-23
  • 2022-12-23
  • 2021-05-23
  • 2021-05-15
  • 2021-08-05
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-06-30
  • 2021-11-13
相关资源
相似解决方案