有向图的邻接矩阵的计算

时间:2023-01-09 15:52:50

自主学习四.实验设计

实验题目:图的邻接矩阵计算

设计方案:

设有向图D=<V,E>,V={v1,v2,…vn}。

如:给定有向图D=<V,E>,

V={a,b,c,d},

E={<a,a>,<a,b>,<a,b>,<a,d>,<d,c>,<c,d>,<c,b>}.

一、需求分析

程序应满足如下功能:

1.能由有向图转换为对应的邻接矩阵。

2.能计算邻接矩阵A,A ²,A ³…A ⁿ.

3.图的邻接矩阵可用来求点到点之间的通路条数。所以程序应能求出点到点之间不同长度的通路条数。

4.能求出点到自身的不同长度的回路条数。

5.能求出长度小于等于n的通路数

6.能求出长度小于等于n的回路数

二、概要设计

1.输入有向图D,将其转换为对应的邻接矩阵。

有向图的输入应包括V,E。可用一维数组存储V;E在后面的计算中不用,一个字符串存储足矣;二维数组存储邻接矩阵。由输入的E与V的关系计算点到点之间的通路数(即邻接矩阵中相应位置的元素)

2.计算邻接矩阵A,A ²,A ³…A ⁿ.

用矩阵乘法算法可求出A,A ²,A ³…A ⁿ.

3.根据A,A ²,A ³…A ⁿ输出所求。

根据矩阵中相应元素的求和等计算可得出所求。

三、详细设计

1.制定输入如下:

有向图的邻接矩阵的计算

图1.1

2.制定菜单如下:

有向图的邻接矩阵的计算

图1.2

3.邻接矩阵的转换算法:

for(int i=0;i<iSize;i++){//遍历E中有向边。

       if(E[i]=='<'){//“<”后元素为起始点

           for(intj=0;j<n;j++){//遍历V,查找起始点

              if(V[j]==E[i+1]){//找到起始点,获取到起始点下标j

                  for(intk=0;k<n;k++){//遍历V,查找终点

                      if(V[k]==E[i+3]){//找到终点,获取到终点下标k

                         A1[j][k]++;//邻接矩阵相应位置+1

                     }

                  }

              }

           }

           i+=4;

       }

    }

2. 计算邻接矩阵A,A ²,A ³…A ⁿ.

这里并不把每一个邻接矩阵A ⁿ都存储下来。根据所需长度求出A ⁿ.

2.1.矩阵乘法算法实现:

//矩阵乘法

void MatMul(int **a,int **b,int **c,intn){

    for(inti=0;i<n;i++){

       for(intj=0;j<n;j++){

           *((int*)c+n*i+j)=0;

           for(intk=0;k<n;k++){

              *((int*)c+n*i+j)+=(*((int *)a+n*i+k))*(*((int *)b+n*k+j));

           }

       }

    }

}

2.2 A ⁿ的计算:

分析如下:

A ²=A*A

A ³= A ²*A

.

.

.

A ⁿ=A(n-1)*A //(n-1)为上标,不能理解学数学的写报告时一堆公式的感受

每次把A(n-1)的计算结果存储为result。

将result复制到临时存储temp

求出A ⁿ

算法实现:

for(int i=2;i<=len;i++){

           MatMul((int**)A1,(int **)temp,(int **)result,n);

           copy((int**)temp,(int **)result,n);

       }

temp=result这里包装成函数,方便调用。算法如下:

//二维数组复制

void copy(int **a,int **b,int n){

    for(inti=0;i<n;i++){

       for(intj=0;j<n;j++){

           *((int*)a+n*i+j)=*((int *)b+n*i+j);

       }

    }

}

3.通路数的计算

点到点之间长度为n的通路(回路)数为矩阵中相应位置元素。

设B=A+A ²+A ³+…+A ⁿ,长度小于等于n的通路为B中各元素之和。

回路为对角线之和。

定义如下变量:

int sum=0;//总和

int partSum=0;//每个A ⁿ矩阵和

int diagonalSum=0;//对角线总和

int diaPartSum=0;//每个A ⁿ矩阵对角线和

算法实现:

for(A~ A ⁿ)

    partSum=sum(A ⁿ);

    sum+=partSum;

diagonalSum+=diaPartSum;

求每个矩阵所有元素之和函数sum()如下:

//矩阵所有元素之和及对角线之和

void Sum(int **a,int *partSum,int*diaPartSum,int n){

    *partSum=0;

    *diaPartSum=0;

    for(inti=0;i<n;i++){

       (*diaPartSum)+=*((int*)a+n*i+i);

       for(intj=0;j<n;j++){

           (*partSum)+=*((int*)a+n*i+j);        

       }

    }

}

四、程序源代码

程序源码为C++语言编写,编译环境为dev-cpp.

#include <iostream>

#include <string>

#include <stdio.h>

using namespace std;

 

/* run this program using the consolepauser or add your own getch, system("pause") or input loop */

void display(int **a,int n){

    for(inti=0;i<n;i++){

       for(intj=0;j<n;j++){

           cout<<*((int*)a+n*i+j)<<" ";

       }

       cout<<endl;

    }

}

//二维数组复制

void copy(int **a,int **b,int n){

    for(inti=0;i<n;i++){

        for(int j=0;j<n;j++){

           *((int*)a+n*i+j)=*((int *)b+n*i+j);

       }

    }

}

//矩阵所有元素之和及对角线之和

void Sum(int **a,int *partSum,int*diaPartSum,int n){

    *partSum=0;

    *diaPartSum=0;

    for(inti=0;i<n;i++){

       (*diaPartSum)+=*((int*)a+n*i+i);

       for(intj=0;j<n;j++){

           (*partSum)+=*((int*)a+n*i+j);        

       }

    }

}

//矩阵乘法

void MatMul(int **a,int **b,int **c,intn){

    for(inti=0;i<n;i++){

       for(intj=0;j<n;j++){

           *((int*)c+n*i+j)=0;

           for(intk=0;k<n;k++){

              *((int*)c+n*i+j)+=(*((int *)a+n*i+k))*(*((int *)b+n*k+j));

           }

       }

    }

}

int main(int argc, char** argv) {

    int n,m;

    cout<<"设有向图D=<V,E>:"<<endl;

    cout<<"请输入顶点个数:";

    cin>>n;

    charV[n];//V

    intA1[n][n];//矩阵

    //初始化A1

    for(inti=0;i<n;i++){

       for(intj=0;j<n;j++){

           A1[i][j]=0;

       }

    }

    //输入D

    stringE; 

    cout<<"请输入V:";

    for(inti=0;i<n;i++){

       cin>>V[i];

    }

    cout<<"请输入E:"<<endl;

    cin>>E;

    //求D的邻接矩阵

    unsignedint iSize=E.length();

    for(inti=0;i<iSize;i++){//遍历E中有向边。

       if(E[i]=='<'){//"<"后元素为起始点

           for(intj=0;j<n;j++){//遍历V,查找起始点

              if(V[j]==E[i+1]){//找到起始点,获取到起始点下标j

                  for(intk=0;k<n;k++){//遍历V,查找终点

                     if(V[k]==E[i+3]){//找到终点,获取到终点下标k

                         A1[j][k]++;//邻接矩阵相应位置+1

                     }

                  }

              }

           }

           i+=4;

       }

    }

    cout<<"*************************************************"<<endl;

    cout<<"1.求长度为n的矩阵"<<endl;

    cout<<"2.求长度为n的通路(回路)"<<endl;

    cout<<"3.求长度小于等于n的通路(回路)"<<endl;

    cout<<"0.退出"<<endl;      

    cout<<"*************************************************"<<endl;

    cout<<"请选择:";

    intoption;

    cin>>option;

    while(option){

       intlen;

       cout<<"请输入长度n:";

       cin>>len;

       inttemp[n][n];

       copy((int**)temp,(int **)A1,n);

       intresult[n][n];

       copy((int**)result,(int **)A1,n);

       intsum=0;//总和

       intpartSum=0;//每个A(n)矩阵和

       intdiagonalSum=0;//对角线总和

       intdiaPartSum=0;//每个A(n)矩阵对角线和

       Sum((int**)A1,&sum,&diagonalSum,n);

       for(inti=2;i<=len;i++){

           MatMul((int**)A1,(int **)temp,(int **)result,n);

           copy((int**)temp,(int **)result,n);

           Sum((int**)result,&partSum,&diaPartSum,n);

           sum+=partSum;

           diagonalSum+=diaPartSum;

       }

       charstart;

       charend;

       switch(option){

           option=0;

           case1:

              display((int**)result,n);

           break;

           case2:

              cout<<"请输入起始点:";

              cin>>start;

              fflush(stdin);

              cout<<"请输入终点:";

              cin>>end;

              for(inti=0;i<n;i++){

                  if(V[i]==start){//获取到起始点下标

                     for(intj=0;j<n;j++){

                         if(V[j]==end){//获取到终点下标

                            stringtempStr="的通路有";

                            if(start==end){

                                tempStr="的回路有";

                            }

                            cout<<"D中"<<start<<"到"<<end

                            <<"长度为"<<len<<tempStr<<result[i][j]<<"条。" <<endl;

                         }

                     }

                  }

              }  

           break;

           case3:

              cout<<"D中长度小于等于" <<len<<"的通路有"<<sum

              <<"条,其中有"<<diagonalSum<<"条回路。"<<endl;

           break;

       }

       cout<<"请选择:";

       cin>>option;

    }  

    return0;

}


五、调试运行:

1.求长度为n的矩阵:

有向图的邻接矩阵的计算

图1.3

2.求长度为n的通路:

有向图的邻接矩阵的计算

图1.4

3.求长度为n的回路:

有向图的邻接矩阵的计算

图1.5

4.求长度小于等于n的通路(回路):

有向图的邻接矩阵的计算

图1.6

5.输入0正常退出程序。

经过多组测试,结果符合实验需求,其余测试结果略。

注意事项:

有向图的邻接矩阵的计算

图1.7

如图,因V的存储采用的字符数组形式,输入V时应输入单个字符,输入E时不应有空格等作为分隔符,有向边用<vi,vj>形式表示。

六、实验总结(略)