有向图D长度为n的通路、回路计算,以及连通性判断

目录

一、基本概念

1、通路

2、回路

3、连通性

4、邻接矩阵

 5、可达矩阵(利用邻接矩阵求)

 二、功能函数

1、创建

2、矩阵乘法

3、求可达矩阵(因为后续判断需要,这里暂不将非零元素变为1)

 4、计算长度为n的通路与回路

 5、判断连通性(简便)

 三、完整代码与样例

1、完整代码

2、样例


一、基本概念

1、通路

  • 在有向图G=<V,E>中,顶点与边的交替序列

2、回路

  • 特殊的通路,起点也是终点

3、连通性

  • 强连通: 在有向图G=<V,E>中,任意一对顶点都可以相互到达。
  • 单向连通性:在有向图G=<V,E>中,任意一对顶点中,至少有一个顶点可以到达另一个顶点
  • 弱连通:对有向图G=<V,E>,若忽略边的方向得到的无向图是强连通,则该有向图是弱连通

 

4、邻接矩阵

  • 利用二维数组储存顶点之间的关系(边或弧)

例:

 5、可达矩阵(利用邻接矩阵求

  • 用矩阵形式来描述有向图的各节点之间经过一定长度的通路后可达到的程度

P(G)=A(G)+A^2(G)+A^3(G)+...+A^n(G)

 二、功能函数

1、创建

void creatgraph(AMGraph *p)
{
    int i,j,k;
    char v1,v2;
    printf("请输入总顶点数:\n");
    scanf("%d",&p->vex);
    printf("请输入总边数:\n");
    scanf("%d",&p->arc);
    printf("请依次输入顶点:\n");k=p->vex;
    for(i=0; i<k; i++)
    {
        getchar();
        scanf("%c",&p->vexs[i]);//依次输入顶点
    }
    for(i=0;i<p->vex;i++)
    {
        for(j=0;j<p->vex;j++)
        {
            p->arcs[i][j]=0;//初始化
        }
    }
    for(k=0;k<p->arc;k++)
    {
        printf("请输入一条边依附的顶点\n");
        getchar();
        scanf("%c %c",&v1,&v2);
        i=locatevex(p,v1);
        j=locatevex(p,v2);  //获取顶点位置
        p->arcs[i][j]=1;
    }
    return 1;
}

2、矩阵乘法

void count(AMGraph *p,AMGraph *t)//矩阵乘法
{
    AMGraph s=*t;
    int i,k,j,sum=0;
    for(i=0;i<p->vex;i++)
    {
        for(k=0;k<p->vex;k++)
        {
            for(j=0;j<p->vex;j++)
            {
                sum+=(s.arcs[i][j])*(p->arcs[j][k]);//行与列相乘
            }
            t->arcs[i][k]=sum;
            sum=0;
        }
    }
}

3、求可达矩阵(因为后续判断需要,这里暂不将非零元素变为1)

void change(AMGraph *p,AMGraph *t)//求可达矩阵
{
    int i,k,j=0;
    AMGraph m=*p;
    while(j<p->vex-1)
    {
        count(p,&m);//求相应阶数的邻接矩阵
        for(i=0;i<p->vex;i++)
        {
            for(k=0;k<p->vex;k++)
            {
                t->arcs[i][k]+=m.arcs[i][k];//将不同阶数的邻接矩阵相加
            }
        }
        j++;
    }
}

 4、计算长度为n的通路与回路

  • 求n-1阶邻接矩阵
  • 对角线元素之和为回路数,所有元素之和为通路数
void jude2(AMGraph *p,int n)//长度为n的通路、回路
{
    int i,k,sum=0;
    AMGraph t=*p;
    for(k=0;k<n-1;k++)
    {
        count(p,&t);
    }

    for(i=0;i<p->vex;i++)
    {
        sum+=t->arcs[i][i];
    }
    if(sum>0)
        printf("该有向图长度为%d的回路有%d个\n",n,sum);
    else
        printf("该有向图没有长度为%d的回路\n",n);
    sum=0;
    for(i=0;i<p->vex;i++)
    {
        for(k=0;k<p->vex;k++)
        {
            sum+=t->arcs[i][k];
        }
    }
    if(sum>=1)
        printf("该有向图长度为%d的通路有%d个\n",n,sum);
    else
        printf("该有向图没有长度为%d的通路\n",n);
}

 5、判断连通性(简便)

  • 强连通:可达矩阵的所有元素非零
  • 弱连通:为每条边(弧)添加一条相反方向的边(弧),然后判断强连通
  • 单向连通:先判断是弱连通,然后通过邻接矩阵判断,若只有一个顶点没有出度,则为单向连通
void jude1(AMGraph *p)//判断连通性
{
    AMGraph t=*p,s=*p,l=*p,q;
    int sign1=0,sign2=0,sign3=0,x=0;
    int i=0,k,j;
    change(p,&t);
    for(i=0;i<p->vex;i++)//强连通
    {
        for(k=0;k<p->vex;k++)
        {
            if(!t.arcs[i][k])
            {
                sign1=1;
                break;
            }
        }
        if(sign1==1)
            break;
    }
    for(i=0;i<p->vex;i++)//将有向图转换为无向图
    {
        for(k=0;k<p->vex;k++)
        {
            if(s.arcs[i][k]==1)
            {
                s.arcs[k][i]=1;
            }
        }
    }
    q=s;
    change(&q,&s);
    for(i=0;i<p->vex;i++)//弱连通
    {
        for(k=0;k<p->vex;k++)
        {
            if(s.arcs[i][k]<1)
            {
                sign3=1;
                break;
            }
        }
        if(sign3==1)
            break;
    }

    if(!sign3&&sign1==1)//单向连通
    {
        for(i=0; i<p->vex; i++)
        {
            for(k=0; k<p->vex; k++)
            {
                if(l.arcs[i][k]==0&&i!=k)//排除自环
                {
                    sign2++;
                }
            }
            if(sign2==p->vex)
            {
                sign2=0;
                x++;
            }
        }

    }
    if(!sign1)
        printf("强连通图\n");
    else if(x==1)
        printf("单向连通图\n");
    else if(!sign3)
        printf("弱连通图\n");
    else printf("不是连通图\n");

}

 三、完整代码与样例

1、完整代码


#include <stdio.h>
#include <stdlib.h>
#define maxsize 100   //最大顶点数

typedef struct
{
    char vexs[maxsize]; //顶点表
    int arcs[maxsize][maxsize]; //邻接矩阵
    int vex;    //图当前的顶点数
    int arc;    //图当前的边数
}AMGraph;


int locatevex(AMGraph *p,char s)
{
    int i;
    for(i=0;i<p->vex;i++)
    {
        if(p->vexs[i]==s)
        {
            return i;
        }
    }
}

void creatgraph(AMGraph *p)
{
    int i,j,k;
    char v1,v2;
    printf("请输入总顶点数:\n");
    scanf("%d",&p->vex);
    printf("请输入总边数:\n");
    scanf("%d",&p->arc);
    printf("请依次输入顶点:\n");k=p->vex;
    for(i=0; i<k; i++)
    {
        getchar();
        scanf("%c",&p->vexs[i]);//依次输入顶点
    }
    for(i=0;i<p->vex;i++)
    {
        for(j=0;j<p->vex;j++)
        {
            p->arcs[i][j]=0;//初始化
        }
    }
    for(k=0;k<p->arc;k++)
    {
        printf("请输入一条边依附的顶点\n");
        getchar();
        scanf("%c %c",&v1,&v2);
        i=locatevex(p,v1);
        j=locatevex(p,v2);  //获取顶点位置
        p->arcs[i][j]=1;
        //p->arcs[i][j]=p->arcs[j][i];//<v1,v2>与<v2,v1>
    }
    return 1;
}

void show(AMGraph *p)
{
    int i,k,count,sign1,sign2=0;
    printf("  ");
    for(i=0;i<p->vex;i++)
    {
        printf("%c ",p->vexs[i]);
    }
    printf("\n");
    for(i=0;i<p->vex;i++)
    {
        printf("%c ",p->vexs[i]);
        for(k=0;k<p->vex;k++)
        {
            printf("%d ",p->arcs[i][k]);
        }
        printf("\n");
    }

}

void count(AMGraph *p,AMGraph *t)//矩阵乘法
{
    AMGraph s=*t;
    int i,k,j,sum=0;
    for(i=0;i<p->vex;i++)
    {
        for(k=0;k<p->vex;k++)
        {
            for(j=0;j<p->vex;j++)
            {
                sum+=(s.arcs[i][j])*(p->arcs[j][k]);
            }
            t->arcs[i][k]=sum;
            sum=0;
        }
    }
}

void change(AMGraph *p,AMGraph *t)//求可达矩阵
{
    int i,k,j=0;
    AMGraph m=*p;
    while(j<p->vex-1)
    {
        count(p,&m);//求相应阶数的邻接矩阵
        for(i=0;i<p->vex;i++)
        {
            for(k=0;k<p->vex;k++)
            {
                t->arcs[i][k]+=m.arcs[i][k];//将不同阶数的邻接矩阵相加
            }
        }
        j++;
    }
}

void jude1(AMGraph *p)//判断连通性
{
    AMGraph t=*p,s=*p,l=*p,q;
    int sign1=0,sign2=0,sign3=0,x=0;
    int i=0,k,j;
    change(p,&t);
    for(i=0;i<p->vex;i++)//强连通
    {
        for(k=0;k<p->vex;k++)
        {
            if(!t.arcs[i][k])
            {
                sign1=1;
                break;
            }
        }
        if(sign1==1)
            break;
    }
    for(i=0;i<p->vex;i++)//将有向图转换为无向图
    {
        for(k=0;k<p->vex;k++)
        {
            if(s.arcs[i][k]==1)
            {
                s.arcs[k][i]=1;
            }
        }
    }
    q=s;
    change(&q,&s);
    for(i=0;i<p->vex;i++)//弱连通
    {
        for(k=0;k<p->vex;k++)
        {
            if(s.arcs[i][k]<1)
            {
                sign3=1;
                break;
            }
        }
        if(sign3==1)
            break;
    }

    if(!sign3&&sign1==1)//单向连通
    {
        for(i=0; i<p->vex; i++)
        {
            for(k=0; k<p->vex; k++)
            {
                if(l.arcs[i][k]==0&&i!=k)//排除自环
                {
                    sign2++;
                }
            }
            if(sign2==p->vex)
            {
                sign2=0;
                x++;
            }
        }

    }
    if(!sign1)
        printf("强连通图\n");
    else if(x==1)
        printf("单向连通图\n");
    else if(!sign3)
        printf("弱连通图\n");
    else printf("不是连通图\n");

}

void jude2(AMGraph *p,int n)//长度为n的通路、回路
{
    int i,k,sum=0;
    AMGraph t=*p;
    for(k=0;k<n-1;k++)
    {
        count(p,&t);
    }
    for(i=0;i<p->vex;i++)
    {
        sum+=t.arcs[i][i];
    }
    if(sum>0)
        printf("该有向图长度为%d的回路有%d个\n",n,sum);
    else
        printf("该有向图没有长度为%d的回路\n",n);
    sum=0;
    for(i=0;i<p->vex;i++)
    {
        for(k=0;k<p->vex;k++)
        {
            sum+=t.arcs[i][k];
        }
    }
    if(sum>=1)
        printf("该有向图长度为%d的通路有%d个\n",n,sum);
    else
        printf("该有向图没有长度为%d的通路\n",n);
}


int main()
{
    AMGraph p;
    int i,n;
    creatgraph(&p);
    printf("请输入要查询的长度:");
    scanf("%d",&n);
    show(&p);
    jude1(&p);//连通性
    jude2(&p,n);//回路与通路
    return 0;
}

2、样例

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

始鸣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值