• 离散实验——关系闭包运算


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

    【实验内容】编程求一个关系的闭包,要求传递闭包用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(" }
    ");
        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("自反闭包:
    ");
        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("对称闭包:
    ");
        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("传递闭包:
    ");
        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("传递闭包:
    ");
        show();
    }
    int main(void)
    {
        printf("请输入集合的元素个数:");
        scanf("%d", &n);
        printf("请输入集合内容:
    ");
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &set[i]);
        }
    
        printf("请输入二元关系的序偶个数:");
        int lon; scanf("%d", &lon);
        printf("请输入集合上的二元关系:
    ");
        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

    一,求自反闭包

    r(R) = R U IA  (IA 为 R 上的恒等关系)

     所以只需要将 关系矩阵 的 主对角线  全部变成 1,就可以了.

    void funR()   // 求 自反闭包
    {
    	initc(r);
    	for (int i = 0; i < n; i++)
    		c[i][i] = 1;
    	printf("自反闭包:
    ");
    	show();
    }
    

     

    二,求对称闭包

    s(R) = R U R'  (这里的 R‘ 是指 R 的逆)

    所以只需要在 关系矩阵 的基础上,若 r(ij) = 1, 则 r(ji) = 1 

     

    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("对称闭包:
    ");
    	show();
    }
    

      

    三,求传递闭包

    这里有两种方法。

    ①  t(R) = R U R2 U R3 U ... U Rn  (这里 Rn 指的是 R的n次幂,n 指的是 R 的 边数,代码中是 点数)

    所以只需要  进行 矩阵的 乘法运算 和 布尔运算 就可以了

    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("传递闭包:
    ");
    	show();
    }
    

    ② 用 warshall方法

    即 枚举途径 某中间顶点 k 的任两个顶点对 i 和 j ,进而通过判断 k->j 是否连接,来判断 是否将 i->j 连接

     然后  ① 若 i->j 已连接,则 k->j 是否连接 并无影响
              ② 若 i->j 没有连接,则 k->j 连接了,则将 i->j 连接

                                            , 则 k->j 没有连接,则不必将 i->j 连接

    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("传递闭包:
    ");
    	show();
    }
    

      

     

     四,补充内容

    1,集合与关系矩阵的对应关系

    通过 一个 set 数组,按顺序对应关系矩阵.

    2, 打印闭包的方法

    其中,遇到的一个问题是 ,没有算完,不知道 “,” 有几个

    所以巧妙运用 flag 进行处理

    3,initc() 

    因为 原先的 关系矩阵 不能 更改。所以需要一个新的 关系矩阵 来

    存 闭包的关系,所以  数组c 就是 这个新的矩阵。

    另外将 c  初始化为 R的关系矩阵 这样处理比较方便,所以 initc() 就是这样一个函数。

     

     

    =========== ========= ======== ======= ====== ===== ==== === == =

    诫子书  诸葛亮(三国) 

     
    夫君子之行,静以修身,俭以养德。非淡泊无以明志,非宁静无以致远。
    夫学须静也,才须学也,非学无以广才,非志无以成学。淫慢则不能励精,险躁则不能治性。
    年与时驰,意与日去,遂成枯落,多不接世,悲守穷庐,将复何及!

     

     

     

  • 相关阅读:
    nohup ./startWebLogic.sh >out.log 2>&1 & 解析
    Eclipse debug 断点不能调试 ,Eclipse Unable to install breakpoint in 解决办法
    Servlet工作原理解析(tomcat7、嵌入式服务器)
    Servlet工作原理
    [Java] SpringMVC工作原理之四:MultipartResolver
    SQLite_安装
    leetcode_315_逆序对问题
    git 学习 3
    dubbo与zookeeper
    Kafka安装
  • 原文地址:https://www.cnblogs.com/asdfknjhu/p/13064348.html
Copyright © 2020-2023  润新知