目录
3、求可达矩阵(因为后续判断需要,这里暂不将非零元素变为1)
一、基本概念
1、通路
- 在有向图G=<V,E>中,顶点与边的交替序列
2、回路
- 特殊的通路,起点也是终点
3、连通性
- 强连通: 在有向图G=<V,E>中,任意一对顶点都可以相互到达。
- 单向连通性:在有向图G=<V,E>中,任意一对顶点中,至少有一个顶点可以到达另一个顶点
- 弱连通:对有向图G=<V,E>,若忽略边的方向得到的无向图是强连通,则该有向图是弱连通
4、邻接矩阵
- 利用二维数组储存顶点之间的关系(边或弧)
例:
5、可达矩阵(利用邻接矩阵求)
- 用矩阵形式来描述有向图的各节点之间经过一定长度的通路后可达到的程度
二、功能函数
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;
}