离散数学实验任务二:求有限集上给定关系的自反、对称和传递闭包(用Warshall算法)(c/c++实现)

问题: 

形如输入字符串“<1,2>,<1,3>,<2,2>,<2,4>,<3,2>”的有限集的关系来求自反、对称和传递闭包。

其中上述关系的有限集为A={1,2,3,4}。

思路:

  1. 自反闭包,在原关系上添加上<x,x>关系即可(x属于任意A中元素)
  2. 对称闭包,原关系中每有一个<x,y>关系,就添加<y,x>关系即可
  3. 传递闭包,利用弗洛伊德—沃舍尔算法(一种动态规划,也可用于求多源最短路)求传递闭包

具体代码实现:

​
#include<iostream>
#include<cstdio>
using namespace std;

const int N=1005;
int g[N][N];
int Size;//矩阵大小

void zifan()
{
    int a[Size+1][Size+1];//临时存自反矩阵
    
    for(int i=1;i<=Size;i++)//初始化
        for(int j=1;j<=Size;j++)a[i][j]=0;
    
    for(int i=1;i<=Size;i++)
    {
        for(int j=1;j<=Size;j++)
        {
            if(i==j)a[i][j]=1;//在原矩阵的基础上,正对角线(i==j)上的i->j全令为有关系,赋值为1
            else a[i][j]=g[i][j];
        }
    }
    
    cout<<"自反闭包"<<endl;
    for(int i=1;i<=Size;i++)//输出自反矩阵
    {
        for(int j=1;j<=Size;j++)cout<<a[i][j]<<' ';
        cout<<endl;
    }
    
    for(int i=1;i<=Size;i++)//输出自反闭包
    {
        for(int j=1;j<=Size;j++)
            if(a[i][j]==1)cout<<'<'<<i<<','<<j<<'>'<<' ';
    }
    cout<<endl;
    
}

void duichen()
{
    int a[Size+1][Size+1];//存临时对称矩阵
    
    for(int i=1;i<=Size;i++)//初始化
        for(int j=1;j<=Size;j++)a[i][j]=0;
    
    for(int i=1;i<=Size;i++)
    {
        for(int j=1;j<=Size;j++)
        {
            if(g[i][j]==1)//原矩阵上i->j有关系,则对称矩阵中i->j,j->i均有关系,赋值为1
                a[i][j]=a[j][i]=1;
        }
    }
    
    cout<<"对称闭包"<<endl;
    for(int i=1;i<=Size;i++)//输出对称矩阵
    {
        for(int j=1;j<=Size;j++)cout<<a[i][j]<<' ';
        cout<<endl;
    }
    
    for(int i=1;i<=Size;i++)//输出对称闭包
    {
        for(int j=1;j<=Size;j++)
            if(a[i][j]==1)cout<<'<'<<i<<','<<j<<'>'<<' ';
    }
    cout<<endl;
    
}

void Floyd_Warshall()//弗洛伊德_沃舍尔算法求传递闭包
{
    int a[Size+1][Size+1];//存临时传递矩阵
    
    for(int i=1;i<=Size;i++)//初始化
        for(int j=1;j<=Size;j++)a[i][j]=g[i][j];
        
    for(int k=1;k<=Size;k++)//枚举每一个中转点
        for(int i=1;i<=Size;i++)//枚举每一个起点
            for(int j=1;j<=Size;j++)//枚举每一个终点
                a[i][j]=a[i][j]|a[i][k]&a[k][j];//i->j的真值 逻辑加 (i->k的真值 逻辑乘 k->j的真值)
    
    cout<<"传递闭包"<<endl;
    for(int i=1;i<=Size;i++)//输出传递矩阵
    {
        for(int j=1;j<=Size;j++)cout<<a[i][j]<<' ';
        cout<<endl;
    }
    
    for(int i=1;i<=Size;i++)//输出传递闭包
    {
        for(int j=1;j<=Size;j++)
            if(a[i][j]==1)cout<<'<'<<i<<','<<j<<'>'<<' ';
    }
    cout<<endl;
}

int main()
{
    string s;
    cin>>s;
    
    for(int i=0;i<s.size();i++)//遍历输入的字符串
    {
        if(s[i]=='<')//每一个'<'说明有一个关系
        {
            int x=s[i+1]-'0',y=s[i+3]-'0';//例如<'x','y'>,'x'表示'<'后面一个字符,'y'表示'<'后面第三个字符,然后减去'0'转化为整型
            Size=max(Size,max(x,y));//最大的元素便是矩阵的大小
            g[x][y]=1;//x->y有关系则赋值为1,无关系全局变量默认为0
        }
    }
    
    cout<<"原关系矩阵"<<endl;
    for(int i=1;i<=Size;i++)//输出原矩阵
    {
        for(int j=1;j<=Size;j++)cout<<g[i][j]<<' ';
        cout<<endl;
    }
    
    cout<<endl;
    zifan();//求自反闭包
    
    cout<<endl;
    duichen();//求对称闭包
    
    cout<<endl;
    Floyd_Warshall();//求传递闭包
    
    return 0;
}

​

案列输入输出:

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。以下是用C语言实现输入关系R的矩阵,计算其自反闭包、对称闭包和传递闭包Warshall算法)的代码: ```c #include<stdio.h> #define MAXSIZE 10 void input(int arr[][MAXSIZE], int n); // 输入矩阵 void output(int arr[][MAXSIZE], int n); // 输出矩阵 void reflexive_closure(int arr[][MAXSIZE], int n); // 计算自反闭包 void symmetric_closure(int arr[][MAXSIZE], int n); // 计算对称闭包 void transitive_closure(int arr[][MAXSIZE], int n); // 计算传递闭包 int main() { int arr[MAXSIZE][MAXSIZE], n; printf("请输入矩阵大小n(n<=10):"); scanf("%d", &n); printf("请输入关系R的矩阵:\n"); input(arr, n); printf("\n关系R的矩阵为:\n"); output(arr, n); reflexive_closure(arr, n); printf("\n自反闭包为:\n"); output(arr, n); symmetric_closure(arr, n); printf("\n对称闭包为:\n"); output(arr, n); transitive_closure(arr, n); printf("\n传递闭包为:\n"); output(arr, n); return 0; } void input(int arr[][MAXSIZE], int n) { int i, j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { scanf("%d", &arr[i][j]); } } } void output(int arr[][MAXSIZE], int n) { int i, j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { printf("%d ", arr[i][j]); } printf("\n"); } } void reflexive_closure(int arr[][MAXSIZE], int n) { int i; for(i=0; i<n; i++) { arr[i][i] = 1; } } void symmetric_closure(int arr[][MAXSIZE], int n) { int i, j; for(i=0; i<n; i++) { for(j=i+1; j<n; j++) { if(arr[i][j] == 1) { arr[j][i] = 1; } else if(arr[j][i] == 1) { arr[i][j] = 1; } } } } void transitive_closure(int arr[][MAXSIZE], int n) { int i, j, k; for(k=0; k<n; k++) { for(i=0; i<n; i++) { for(j=0; j<n; j++) { arr[i][j] = arr[i][j] || (arr[i][k] && arr[k][j]); } } } } ``` 希望这个代码可以帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值