如何编程求有向图的单向连通分支。
如果在一个有向图中取一组顶点,满足:
(1).其中,任意甲乙两点间,一定存在其中一点至另一点的通路(即存在甲至乙或乙至甲的通路)。
(2).如果再向该组点中加入该图的其他点后,则一定存在两点间没有任何单向连通的通路。
则称这一组点构成该有向图的一个单向连通分支。
#include <stdio.h>
#define MAX_VEX_NUM 20
/*图的结构*/
typedef struct graph{
int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; /*邻接距阵*/
int vex_num; /*顶点数*/
}Graph;
Graph g; /*全局变量*/
/*构造集合*/
typedef struct collention{
int vexs[MAX_VEX_NUM];
int num; /*集合中间的结点数*/
}Vexset;
Vexset vexset[MAX_VEX_NUM];
int flag[MAX_VEX_NUM];/*标志结点是否被添加到集合中*/
/*初始化标志位*/
void initflag(Graph *g){
int i;
for(i=0;i<g->vex_num;i++){
flag[i]=0;
}
}
/*添加结点到集合中*/
void addToSet(int i,Vexset *s){
s->vexs[s->num]=i;
s->num++;
}
void swap(int *i,int *j){
int temp;
temp=*i;
*i=*j;
*j=temp;
}
/*对集合中的元素进行排序*/
/*采用冒泡法*/
void sortSet(Vexset *s){
int i;
int j;
for(i=0;i<s->num;i++){
for(j=0;j<i;j++){
if(s->vexs[j]>s->vexs[j+1]){
swap(&(s->vexs[j]),&(s->vexs[j+1]));
}
}
}
}
/*判断两个集合是否相等*/
int judgeEquals(Vexset *s1,Vexset *s2){
int k;
int result=1;
/*先判断集合个数是否一样*/
if(s1->num!=s2->num){
result=0;
}
else{
/*再判断相同位置上的元素是否相等*/
for(k=0;k<s1->num;k++){
if(s1->vexs[k]!=s2->vexs[k]){
result=0;
}
}
}
return result;
}
/*-----初始化图------*/
void initGraph(Graph *g){
int i;
int j;
printf("请输入图的结点数:");
scanf("%d",&g->vex_num);
printf("说明:请输入邻接矩阵,只能输0,1/n");
printf(" 由于是简单有向图,所以矩阵对角线上只能是0/n");
printf(" 而且邻接矩阵都只能有0,1构成的/n");
for(i=0;i<g->vex_num;i++){
for(j=0;j<g->vex_num;j++){
if(i==j){
g->arcs[i][j]=0; /*简单图不存在环*/
}
else{
printf("请输入邻接矩阵坐标为(%d,%d):",i,j);
scanf("%d",&g->arcs[i][j]);
}
}
}
}
/*测试输入的值*/
void printMatrix(Graph *g){
int i; /*计数器*/
int j; /*计数器*/
for(i=0;i<g->vex_num;i++){
for(j=0;j<g->vex_num;j++){
printf("%d ",g->arcs[i][j]);
}
printf("/n");
}
}
/*
获得可达矩阵
可达矩阵:若i与j之间存在通路,则A[i,j]为1,否则为0;
若邻接矩阵是N*N的,则进行N次叠代
其中:
A0[i,j]表示邻接矩阵
Ak[i,j]表示k次叠代后的A[i,j]的值
Ak[i,j]=Ak-1[i,j]||(Ak-1[i,k]&&Ak-1[k,j])
*/
void getRecMatrix(Graph *g){
int vex_num = g->vex_num;
int k;
int i;
int j;
for(k=0;k<vex_num;k++){
for(i=0;i<vex_num;i++)
for(j=0;j<vex_num;j++){
if(i!=j){
g->arcs[i][j] = g->arcs[i][j]|(g->arcs[i][k]&g->arcs[k][j]);
}
}
}
}
/*
判断两个结点之间是否连通
*/
int isConnect(int i,int j,Graph *g){
return g->arcs[i][j];
}
void main(){
int i;
int j;
int k;/*计数器*/
int canadd;/*控制是否能添加到集合中*/
int canprint;/*控制能否打印*/
initGraph(&g);
printf("该图的邻接矩阵为:/n");
printMatrix(&g);
printf("该图的可达矩阵为:/n");
getRecMatrix(&g);
printMatrix(&g);
/*
放入集合中的点就表示都是单连通的,
即任意的i,j属于集合,若<i,j>不属于集合则,<j,i>属于集合
做贪心搜索,发现与集合中的任意点都单连通的点就放入集合中
在将该点从原来的图中逻辑删除,即将flag[i]设为1
*/
for(i=0;i<g.vex_num;i++){
initflag(&g);
addToSet(i,&vexset[i]);
flag[i]=1;
for(j=0;j<g.vex_num;j++){
if(flag[j]==0){
canadd=1;
for(k=0;k<vexset[i].num;k++){
if(!isConnect(j,vexset[i].vexs[k],&g)&&!isConnect(vexset[i].vexs[k],j,&g)){
canadd=0;/*表示不满足添加到集合的条件*/
}
}
if(canadd==1){
addToSet(j,&vexset[i]);
flag[j]=1;
}
}
}
}
printf("连通分支有:/n");
/*
for(i=0;i<g.vex_num;i++){
printf("(");
for(j=0;j<vexset[i].num;j++){
printf("%d,",vexset[i].vexs[j]);
}
printf(")/n");
}
printf("-------------------/n");
*/
for(i=0;i<g.vex_num;i++){
sortSet(&vexset[i]);
canprint=1;
for(k=0;k<i;k++){
if(judgeEquals(&vexset[k],&vexset[i])){
// printf("sadffsd/n");
canprint=0;
}
}
if(canprint){
printf("(");
for(j=0;j<vexset[i].num;j++){
printf("%d,",vexset[i].vexs[j]);
}
printf(")/n");
}
}
}