实验6 图的应用
分别提交两个附件:
1:设计文档(提交PDF格式的文件,文件名要规范,参看规范)。
2:实验源码包。(文件名也要规范,可以参考报告文件的格式)
实验6 通信网络
一、问题分析
分析并确定要处理的对象(数据)是什么
输入的数据分别为部门的个数和部门之间关系的数量,此外还有存在关系的部门的编号。考虑到数据之间多对多的关系,考虑采用图的数据结构储存,故需要处理的数据转化为图的结点和各个结点之间的权值。
分析并确定要实现的功能是什么
根据题目意思,不同的部门之间存在单向消息传递的关系,而存在传递关系的部门知道彼此的存在,不能互传消息的部门不知道彼此存在,我们需要统计知道所有部门的存在的部门个数,实则需要我们统计,这个图中的所有节点,有多少个和其他所有节点有关系(其他节点可以或直接或间接地到达或者被该节点传达消息)。
分析并确定处理后的结果如何显示
根据题目意思,直接输出一个知道所有部门的部门数量即可。
二、数据结构和算法设计
抽象数据类型设计
考虑到数据之间多对多的关系,可以采用图的数据结构储存。该图可以通过邻接矩阵的实现方法进行实现。
物理数据对象设计(不用给出基本操作的实现)
采用邻接矩阵实现数据之间的关系储存。通过整型的**matrix存储结点之间的关系,即结点间的权值,其初始值为0。
用两个整型变量numvertex,numedge,分别存储图的结点数和边数。
输入边权值的同时,将权值存储在矩阵中,即可完成图关系的建立。
算法思想的设计
本题要实现可间接到达的结点即有关系,并最终统计和所有结点都有关系的结点的个数。
【步骤1.】可直接到达的结点之间的关系已经存储在了邻接矩阵中,接下来只要考虑如何将可间接到达的结点在矩阵中建立起关系即可。初步设计是,若存在A->B,B->C两条直达边,那么在A,C之间也建立起一条边,使A->B可直达,即A,B之间存在A到B的关系。
如样例中所示,以2为中转结点,1->2可直达,2->4可直达,那么就建立起一条新的边1->4,让1->4可以直达,如图所示:
【步骤2.】所有结点都可以自己到达自己(即所有部门都知道自己部门存在),通过setedge(v,v)实现即可。
【步骤3.】对所有结点进行如此的遍历,以结点i为中转结点,将可以到达i的j结点和i可以到达的k结点直接连起来,建立j->k的新节点。
【步骤4.】如此则建立起了从起点到终点之间,路径上中间结点的关系建立。接下来考虑逆向的关系建立。(如A->B通过矩阵(A,B)值为1,但根据题目意思,B和A之间也是存在可传递的练习的,此时矩阵(B,A)还没有表现出来,我们可以根据刚才正向的矩阵关系建立)。
通过双层for循环对所有结点进行遍历,如果(A,B)存在关系,但(B,A)值为0,则通过setedge(B,A,1)建立逆向关系。
【步骤5.】此时,正向和逆向的关系都已经实现。再次对numvertex个结点进行遍历,若这个结点和所有结点都有关系,则计数遍历sum++,遍历完成后输出sum即可。
请用题目中样例,基于所设计的算法,详细给出样例求解过程。
1.将所有结点的关系存储在矩阵中,矩阵如图所示:
2.所有结点可以到达本身,矩阵更新如下:
3.间接到达的边1->4可通过中转结点2或者3,完成直达边的建立。如图所示:
4.完成逆向关系的建立,矩阵更新如下:
5.对四个结点和其他节点的关系进行判断,若此结点和其他所有结点都有关系,则初值为0的sum变量+1,如上图矩阵所示,结点1和结点4和四个结点都有关系,sum值为2。输出2。
关键功能的算法步骤(不能用源码)
【步骤3】中采用三重循环遍历,完成间接结点之间的直接关联。伪代码如下:
for(int i = 0 ; i < numv ; i++)
{
for(int j = 0 ; j < numv ; j++)
{
if(mymap.isedge(j,i))
{
for(int k = 0 ; k < numv ; k++)
{
if(mymap.isedge(i,k)&&!mymap.isedge(j,k))
mymap.setedge(j,k,1);
}
}
}
}
【步骤4】逆向关系矩阵的更新,伪代码如下:
for(int i = 0 ; i < numv ; i++)
{
for(int j = 0 ; j < numv ; j++)
{
if(mymap.isedge(i,j)&&!mymap.isedge(j,i))
mymap.setedge(j,i,1);
}
}
三、算法性能分析。
1.将|E|个结点存储在矩阵中,时间复杂度T=|E|
2.步骤3中通过三重遍历实现间接结点的连接,时间复杂度T=
3.步骤4中通过双重循环实现逆向矩阵的实现,时间复杂度T=
4.通过双重循环判断结点是否和所有结点相连,时间复杂度T=
5.总的时间复杂度T=|E|++2,化简后时间复杂度为O(|E|+)
6.算法过程中开辟了一个大小为|E|的二维数组存储边权,时间复杂度为O(|E|)
代码实现部分:
graph.h
#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED
#include <iostream>
class graph
{
private:
void operator = (const graph&){}
graph(const graph&){}
public:
graph(){}
virtual ~graph(){}
virtual void init(int n) =0;
virtual int n() = 0;
virtual int e() = 0;
virtual int first(int v) = 0;
virtual int next(int v,int w) = 0;
virtual void setedge(int v1,int v2,int wght) = 0;
virtual void deledge(int v1,int v2) = 0;
virtual bool isedge(int i,int j) = 0;
virtual int weight(int v1,int v2) = 0;
virtual void setmark(int v,int val) = 0;
virtual void print() = 0;
virtual int find_out() = 0;
virtual int find_out_num() = 0;
virtual void find_know() = 0;
};
#endif // GRAPH_H_INCLUDED
graphm.h
#ifndef GRAPHM_H_INCLUDED
#define GRAPHM_H_INCLUDED
#define UNVISITED 0
#include "graph.h"
#include <iostream>
using namespace std;
class graphm : public graph//脕脷陆脫戮脴脮贸
{
private:
int numvertex,numedge;
int **matrix;
int *mark;
public:
graphm(int numvert)
{
init(numvert);
}
~graphm()
{
delete []mark;
for(int i = 0 ; i < numvertex; i++)
delete [] matrix[i];
delete [] matrix;
}
void init(int n)
{
int i;
numvertex = n;
numedge = 0;
mark = new int [n];
for(i = 0 ; i < numvertex; i++)
mark[i] = UNVISITED;
matrix = (int**)new int *[numvertex];
for(i = 0 ; i < numvertex ; i++)
matrix[i] = new int[numvertex];
for(i = 0 ; i < numvertex ; i++)
for(int j = 0; j < numvertex; j++)
matrix[i][j] = 0;
}
int n() {return numvertex;}
int e() {return numedge;}
int first(int v)
{
for(int i = 0; i < numvertex; i++)
if(matrix[v][i] != 0)
return i;
return numvertex;
}
int next(int v,int w)
{
for(int i = w+1; i < numvertex; i++)
if(matrix[v][i] != 0)
return i;
return numvertex;
}
void setedge(int v1,int v2,int wt)
{
//Assert(wt > 0,"Illegal weight value");
if(matrix[v1][v2] == 0) numedge++;
matrix[v1][v2] = wt;
}
void deledge(int v1,int v2)
{
if(matrix[v1][v2] != 0) numedge--;
matrix[v1][v2] = 0;
}
bool isedge(int i,int j)
{
return matrix[i][j] != 0;
}
void print()
{
for(int i = 0 ; i < numvertex ; i++)
{
for(int j = 0 ; j < numvertex ; j++)
{
cout << matrix[i][j] << " ";
}
cout << endl;
}
}
int find_out()
{
int answer = 0;int mymax = 0;
for(int i = 0 ; i < numvertex ; i++)
{
int sum = 0;
for(int j = 0 ; j < numvertex ; j++)
if(matrix[i][j] != 0) sum++;
if(mymax <= sum)
{
answer = i ;
mymax = sum;
}
}
return answer;
}
int find_out_num()
{
int answer = 0;int mymax = 0;
for(int i = 0 ; i < numvertex ; i++)
{
int sum = 0;
for(int j = 0 ; j < numvertex ; j++)
if(matrix[i][j] != 0) sum++;
if(mymax <= sum)
{
answer = sum ;
mymax = sum;
}
}
return answer;
}
void find_know()
{
int sum = 0;
for(int i = 0 ;i < numvertex ; i++)
{
int mymax = 0;
for(int j = 0 ; j < numvertex ; j++)
{
if(matrix[i][j] == 1)
mymax++;
}
if(mymax == numvertex)
sum++;
}
cout << sum << endl;
}
int weight(int v1,int v2) {return matrix[v1][v2];}
int getmark(int v) {return mark[v];}
void setmark(int v,int val) {mark[v] = val;}
};
#endif // GRAPHM_H_INCLUDED
main.c
#include <iostream>
#include "graphm.h"
using namespace std;
int main()
{
int numv,nume;
cin >> numv >> nume;
graphm mymap(numv);
int key[nume][2];
for(int i = 0 ; i < nume ; i++)
{
cin >> key[i][0] >> key[i][1];
key[i][0]--; key[i][1]--;
mymap.setedge(key[i][0],key[i][1],1);
}
for(int i = 0 ; i < numv ; i++)
mymap.setedge(i,i,1);
for(int i = 0 ; i < numv ; i++)
{
for(int j = 0 ; j < numv ; j++)
{
if(mymap.isedge(j,i))
{
for(int k = 0 ; k < numv ; k++)
{
if(mymap.isedge(i,k)&&!mymap.isedge(j,k))
mymap.setedge(j,k,1);
}
}
}
}
for(int i = 0 ; i < numv ; i++)
{
for(int j = 0 ; j < numv ; j++)
{
if(mymap.isedge(i,j)&&!mymap.isedge(j,i))
mymap.setedge(j,i,1);
}
}
mymap.find_know();
return 0;
}