离散数学实验四c语言(计算可达矩阵,判断性质:强连通性、单侧联通性质、无联通性质、弱联通性质)

一、算法描述、算法思想

(一)相关数据结构
cpp 复制代码
#define TotalVertex 100
int n, totaledge;

定义数组初始化的点数为TotalVertex,n代表总的点的数目,totaledge代表边的数量。

cpp 复制代码
int g[TotalVertex][TotalVertex] = {0};  // 邻接矩阵
int f[TotalVertex][TotalVertex] = {0};  // 可达矩阵
int gw[TotalVertex][TotalVertex] = {0}; // 无向图的邻接矩阵
int fw[TotalVertex][TotalVertex] = {0}; // 无向图的可达矩阵

以上为四个数组的定义,分别为邻接矩阵、可达矩阵、将有向图转换为无向图的邻接矩阵、可达矩阵

(二)相关算法实现
1、计算可达矩阵
cpp 复制代码
void OperatorAviG(int g[][TotalVertex], int f[][TotalVertex])
{
    // 计算可达矩阵
    int tmp[TotalVertex][TotalVertex];
    memcpy(tmp, g, sizeof(tmp));
    for (int i = 1; i < n; i++)
    {
        MuliG(g, tmp);
        AddG(f, g);
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (f[i][j] > 1)
                f[i][j] = 1;
        }
    }
}

(1)首先先将邻接矩阵复制一份到tmp数组

(2)因为此题求的为简单有向图的连通性质,因此两点间的距离不会大于点的个数(n),所以将邻接矩阵相乘n次即可

(3)每一次相乘邻接矩阵,将所得的矩阵复制到g中,然后因此tmp此时为原先的邻接矩阵,所以可以借助其继续相乘

(4)每次相乘后,将所得的矩阵g与矩阵f相加(f矩阵的初始值为邻接矩阵的值)

(5)这样处理n次后,再对f矩阵处理,f矩阵此时的值为邻接矩阵乘以1-n次后所有矩阵值的相加,将f矩阵中有数字的值全改为1,即为两点之间可达。因此f就为邻接矩阵g的可达矩阵

2、性质判断
cpp 复制代码
void Operate()
{
    OperatorAviG(g, f);
    OperatorAviG(gw, fw);

    printf("可达矩阵为:\n");
    PrintG(f);
}

首先先将有向图的邻接矩阵g的可达矩阵求出,然后将有向图转换为无向图后,再将其邻接矩阵gw的可达矩阵fw求出

cpp 复制代码
void PanAviG()
{
    int panq = 0, pand = 0, panr = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (f[i][j] == 0)
                panq = 1; // 为1表示不为强连通
            if (f[i][j] == 1)
                pand = 1; // 为1表示可以为单侧连通
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (fw[i][j] == 0)
                panr = 1; // 为1表示不为弱连通
        }
    }
    printf("图的连通性质为:\n");
    if (!panq)
        printf("为强连通\n");
    if (pand)
        printf("为单连通\n");
    if (!panr)
        printf("为弱连通\n");
    if (panq && !pand && panr)
        printf("该图无连通性质\n");
}

(1)首先先根据有向图的可达矩阵来判断该图是否为强连通和单侧连通,若图中存在两点有边,则说明为单侧连通的;若图中存在两点间无边,则说明该图不为强连通的。

(2)然后是根据无向图的可达矩阵来判断该图是否具有弱连通。若无向图的可达矩阵中,存在两点无边,则说明该图不为弱连通

(三)流程图
1、main函数
2、InitEdge()(初始化图)
3、OperatorAviG(将邻接矩阵转换为可达矩阵)
4、Operate()(计算边的性质)
5、PanAviG()(判断图的连通性)

二、程序运行截图,及相关样例解释

(一)验证程序判断图强连通性质的准确性

若为强连通,其单侧连通,弱连通的性质也必定满足

(二)验证程序判断图单侧连通性质的准确性

通过分析可以发现该矩阵为单侧连通的,程序输出满足要求。

(三)验证程序判断图无连通性质的准确性

通过分析,可以看出该图不具有连通性,程序输出满足要求。

(四)验证程序判断图弱连通性质的准确性

弱连通也有边相连,因此也为单侧连通的,程序输出满足要求。

三、源程序

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TotalVertex 100
int n, totaledge;
int g[TotalVertex][TotalVertex] = {0};  // 邻接矩阵
int f[TotalVertex][TotalVertex] = {0};  // 可达矩阵
int gw[TotalVertex][TotalVertex] = {0}; // 无向图的邻接矩阵
int fw[TotalVertex][TotalVertex] = {0}; // 无向图的可达矩阵
void PrintG(int tmp[][TotalVertex])
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            printf("%d ", tmp[i][j]);
        printf("\n");
    }
}
void ConvertW(int tmp[][TotalVertex])
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (tmp[i][j] == 1)
                tmp[j][i] = 1;
        }
    }
}
void InitEdge()
{
    printf("请按照起点->终点的顺序顺序输入边,注意编号范围为1-结点数\n(eg:1 2,表示1到2有一条边)\n");
    for (int i = 1; i <= totaledge; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        g[x][y] = 1;
    }
    printf("邻接矩阵为:\n");
    PrintG(g);
    memcpy(f, g, sizeof(f));

    memcpy(gw, g, sizeof(gw));
    ConvertW(gw);
    memcpy(fw, gw, sizeof(fw));
}
void MuliG(int g1[][TotalVertex], int g2[][TotalVertex])
{
    int tmp[TotalVertex][TotalVertex] = {0};
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            for (int k = 1; k <= n; k++)
                tmp[i][j] += (g1[i][k] * g2[k][j]);
        }
    }
    memcpy(g1, tmp, sizeof(g));
}
void AddG(int f[][TotalVertex], int g[][TotalVertex])
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            f[i][j] += g[i][j];
    }
}
void OperatorAviG(int g[][TotalVertex], int f[][TotalVertex])
{
    // 计算可达矩阵
    int tmp[TotalVertex][TotalVertex];
    memcpy(tmp, g, sizeof(tmp));
    for (int i = 1; i < n; i++)
    {
        MuliG(g, tmp);
        AddG(f, g);
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (f[i][j] > 1)
                f[i][j] = 1;
        }
    }
}
void Operate()
{
    OperatorAviG(g, f);
    OperatorAviG(gw, fw);

    printf("可达矩阵为:\n");
    PrintG(f);
}
void PanAviG()
{
    int panq = 0, pand = 0, panr = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (f[i][j] == 0)
                panq = 1; // 为1表示不为强连通
            if (f[i][j] == 1)
                pand = 1; // 为1表示可以为单侧连通
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (fw[i][j] == 0)
                panr = 1; // 为1表示不为弱连通
        }
    }
    printf("图的连通性质为:\n");
    if (!panq)
        printf("为强连通\n");
    if (pand)
        printf("为单连通\n");
    if (!panr)
        printf("为弱连通\n");
    if (panq && !pand && panr)
        printf("该图无连通性质\n");
}
int main()
{
    printf("请输入节点总数");
    scanf("%d", &n);
    printf("请输入边的总数");
    scanf("%d", &totaledge);
    InitEdge();

    Operate();
    PanAviG();

    return 0;
}
相关推荐
Niuguangshuo3 小时前
论文解读:CTC,端到端序列识别的开山之作
算法·语音识别
讳疾忌医丶4 小时前
深度拆解 RocksDB 内核:基于 C++17 的 FIFO 调度状态机与温度阶梯自愈设计
java·c++·算法·架构
高亦真4 小时前
今天是学习嵌入式的第37天
linux·学习·算法
罗西的思考6 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 --- (2)--- 训练
人工智能·算法·机器学习
深圳市方中禾科技7 小时前
FZH1625 LCD 驱动芯片深度评测与实战指南
算法·led
我不会起名字3228 小时前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣
IT小白杨8 小时前
社媒多账号运营的环境隔离:一张图谱模型,解释清“为什么换IP还是被连坐“
经验分享·笔记·矩阵·指纹浏览器
云泽8088 小时前
STM32 USART 详解(八):C I/O 串口重定向原理与实现
c语言·stm32·嵌入式硬件
ThornArmor8 小时前
重铸1996|肉体渲染:关节的裂缝:分段模型积木拼装与未成熟的 RSP 矩阵骨骼动画形变
c语言·汇编·c++·python·硬件架构·游戏机
T1mzhou8 小时前
ARM64 Linux 6.10 内核驱动(12):dd.c:probe/ remove、延迟 probe
linux·服务器·c语言·arm开发·arm