DS博客作业04--图

| 这个作业属于哪个班级 | 数据结构--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | DS博客作业04--图 |
| 这个作业的目标 | 学习树结构设计及运算操作 |
| 姓名 | 章审 |

0.PTA得分截图

1.本周学习总结

1.端点和邻接点
无向图:若存在一条边(i,j),则称顶点i和顶点j互为邻接点。
有向图:存在一条边<i,j>,则此边是顶点i的一条出边,同时也是顶点j的一条入边;称顶点i和顶点j互为邻接点。
2.顶点的度、入读和出度
无向图:以顶点i为端点的边数称为该顶点的度。
有向图:以顶点i为终点的入边的数目,称为该顶点的入度。以顶点i为始点的出边的数目,称为该顶点的出度。一个顶点的入度与出度的和为该顶点的度。
3.完全图
无向图:每两个顶点之间都存在着一条边,称为完全无向图,包含有n(n-1)/2条边。
有向图:每两个顶点之间方向相反的两条边,称为完全有向图,包含n(n-1)条边。
4.稠密图、稀疏图
当一个图接近完全图时,则称为稠密图。
相反,当一个图含有较少的边数(即当e<<n(n-1))时,则称为稀疏图。
5.子图
设有两个图G=(V,E)和G'=(V',E'),若v'是V的子集,即V'属于V,且E'是E的子集,即E'属于E,则称G'是G的子图。
6.路径和路径长度
从顶点i到顶点j的一条路径是一个顶点序列(i,i1,i2,...,im,j),序列中边(i,i1),(i1,i2),...,(im-1,im),(im,j)属于E(G);
路径长度是指一条路径上经过的边的数目;
简单路径:一条路径上除开始点和结束点可以相同外,其余顶点均不相同。
7,回路或环
回路或环:一条路径上的开始点结束点为同一个顶点。
简单回路或简单环:开始点与结束点相同的简单路径。
8、连通、连通图和连通分量
无向图:若从顶点,顶点有路径,则称顶点潮j是连通的。
连通图:若图中任意两个顶点都连通,否则称为非连通图。
连通分量:无向图G中的极大连通子图。
任何连通图的连通分量只有一个,即本身。
而非连通图有多个连通分量。
图1:

1.1 图的存储结构

1.1.1 邻接矩阵

1.造一个图,展示其对应邻接矩阵
如图1所示,其邻接矩阵为:

2.邻接矩阵的结构体定义

#define MAXV<最大顶点个数>
#define INF 32767        //定义∞
typedef struct 
{
	int no;                  //顶点的编号
	InfoType info;          //顶点的其他信息
} VertexType;            //顶点的类型
typedef struct 
{
	int edges[MAXV][MAXV];  //邻接矩阵数组
	int n, e;                //顶点数,边数
	VertexType vexs[MAXV];  //存放顶点信息
} MatGraph;              //完整的图邻接矩阵类型

3.建图函数

void Create(MGraph* G)
{
	int i, j;
	printf("输入顶点数和边数:\n");
	scanf("%d%d", &G->numVertexes, &G->numEdges);  //输入顶点信息,创建顶点表 
	printf("输入顶点信息:\n");
	for (i = 0; inumVertexes; i++) 
        {
		getchar();
		scanf("%c", &G->vexs[i]);
	}

	//输入邻接矩阵
	printf("输入邻接矩阵:\n");
	for (i = 0; inumVertexes; i++) 
        {
		for (j = 0; jnumVertexes; j++) 
                {
			scanf("%d", &G->arc[i][j]);
			if (G->arc[i][j] == 0)
				G->arc[i][j] = FINITY;
		}
	}
}

1.1.2 邻接表

1.造一个图,展示其对应邻接表
如图1所示,其邻接表为:

2.邻接表的结构体定义

typedef struct ANode
{
	int adjvex;               //该边的邻接点编号
	struct ANode* nextarc;   //指向下一条边的指针
	int weight;               //该边的相关信息,如权值(这里用整型表示)
}ArcNode;                 //边结点的类型
typedef struct Vnode
{
	InfoType info;            //顶点的其他信息
	ArcNode* firstarc;       //指向第一个边结点
} VNode;                  //邻接表的头结点类型
typedef struct
{
	VNode adjlist[MAXV];      //邻接表的头结点数组
	int n, e;                 //图中的顶点数n和边数e
}AdjGraph;                //完整的图邻接表类型

3.建图函数

void CreateAdj(AdjGraph*& G, int A[MAXV[MAXV], int n, int e) //创建图的邻接表
{
	int i, j; ArcNode* p;
	G = (AdjGraph)malloc(sizeof(AdjGraph));
	for (i = 0; i < n; i++)                                            //给邻接表中所有头结点的指针域置初值
		G→ > adjlist[i].firstarc = NULL;
	for (i = 0; i < n; i++)                                            //检查邻接矩阵中的每个元素
		for (j = n - 1; j >= 0; j--)
			if (A[][] != o && A[iG != INF)                     //存在—条边
			{
				p = (ArcNode*)malloc(sizeof(ArcNode));     //创建一个结点p
				p->adjvex = j;                              //存放邻接点
				p->weight = A[i][j];                        //存放权
				p->nextarc = G->adjlist[i].firstarc;        //采用头插法插人结点p
				G->adjlist[i].firstarc = p;
				G->n = n;
				G->e = e;
			}
}

1.1.3 邻接矩阵和邻接表表示图的区别

邻接矩阵的特点如下:
(1)图的邻接矩阵表示是唯一的。
(2)对于含有n个顶点的图,当采用邻接矩阵存储时,无论是有向图还是无向图,也无论边的数目是多少,其存储空间都为O(n) ,所以邻接矩阵适合于存储边的数目较多的稠密图
(3)无向图的邻接矩阵数组一定是一个对称矩阵,因此可以采用压缩存储的思想,在存放邻接矩阵数组时只需存放上(或下)三角部分的元素即可。
(4)对于无向图,邻接矩阵数组的第i行或第i列非零元素、非00元素的个数正好是顶ii的度。
(5)对于有向图,邻接矩阵数组的第i行(或第i列)非零元素、非0元素的个数正好是顶点i的出度(或入度)。
(6)在邻接矩阵中,判断图中两个顶点之间是否有边或者求两个顶点之间边的权的执行时间为0(1),所以在需要提取边权值的算法中通常采用邻接矩阵存储结构。
邻接表的特点如下:
(1)邻接表的表示不唯一,这是因为在每个顶点对应的单链表中各边结点的链接次序可以是任意的,取决于建立邻接表的算法以及边的输入次序。
(2)对于有n个顶点和e条边的无向图,其邻接表有n个头结点和2e个边结点;对于有n个顶点和e条边的有向图,其邻接表有n个头结点和e个边结点。显然,对于边数目较少的稀疏图,邻接表比邻接矩阵更节省存储空间。
(3)对于无向图,邻接表中顶点i对应的第i个单链表的边结点数目正好是顶点i的度。
(4)对于有向图,邻接表中顶点i对应的第i个单链表的边结点数目仅仅是顶点i的出度。顶点i的人度为邻接表中所有adjvex域值为i的边结点数目。
(5)在邻接表中,查找顶点i关联的所有边是非常快速的,所以在需要提取某个顶点的所有邻接点的算法中通常采用邻接表存储结构。

1.2图遍历

1.2.1 深度优先遍历

1.选上述的图,继续介绍深度优先遍历结果
初始点从1开始的深度遍历:123465。
2.深度遍历代码

int visited[MAX] = { 0 };            //全局数组
void DFS(AdjGraph* G, int v)      //深度优先遍历算法
{
	ArcNode* p;
	visited[v] = 1;                     //置已访问标记
	printf("%d ", v)                   //输出被访问顶点的编号
		p - G → > adjlist[v].firstarc;     //p指向顶点v的第一个邻接点
	while (p != NULL)
	{
		if (visited[p→ > adjvex) == 0)        //若p->adjvex顶点未被访问,递归访问它
		DFS(G, p->adjvex);
		p = p->nextarc;                    //p指向顶点v的下一个邻接点
	}
}

3.深度遍历适用哪些问题的求解
深度遍历适用于解决访问初始点v后再访问与定点v相邻的顶点w,再以w为初始点去访问w的相邻点。例如迷宫、六度空间等等。

1.2.2 广度优先遍历

1.选上述的图,继续介绍广度优先遍历结果
初始点从1开始的广度遍历:123645。
2.广度遍历代码

void BFS(AdjGraph* G, int v)
{
	int w, i; ArcNode* p;
	SqQueue qu;                       //定义环形队列指针
	InitQueue(qu);                    //初始化队列
	int visited[MAXV];                //定义顶点访问标记数组
	for (i = 0; i < G->n; i++)
		visited[i] = 0;                     //访问标记数组初始化
	printf("%2d", v);                  //输出被访问顶点的编号
	visited[v] = 1;                   //置已访问标记
	enQueue(qu, v);
	while (!QueueEmpty(qu)            //队不空循环
	{
		deQueue(qu, w);                   //出队一个顶点w
		p = G→ > adjlist[w].firstarc;        //指向w的第一个邻接点
		while (p != NULL)                   //查找w的所有邻接点
		{
			if (visited[p->adjvex] == 0)        //若当前邻接点未被访向
			{
				printf("%2d", p->adjvex);         //访问该邻接点
				visited[p->adjvex] = 1;             //置已访问标记
				enQueue(qu, p->adjvex);           //该顶点进队
			}
			p = p→ > nextare;                    //找下一个邻接点
		}
	}
	printf("\n");
}

3.广度遍历适用哪些问题的求解。
广度遍历适用于先访问初始点v,接着访问顶点v的所有未被访问过的邻接点v1,v2...vt,然后再按v1,v2...vt的次序访问每一个顶点的所有未被访问过的邻接点。例如求不带权无向连通图中的两个顶点的最短路径、求不带权无向连通图中距离一个顶点v的最远顶点等等。

1.3 最小生成树

最小生成树:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。
最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。

1.3.1 Prim算法求最小生成树

1求Prim算法生成的最小生成树的边序列
普里姆(Prim)算法是一种构造性算法,假设G=(V,E)是一个具有n个顶点的带权连通图,T=(U, TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则由G构造从起始点v出发的最小生成树T的步骤如下:
(1)初始化U={2},以v到其他顶点的所有边为候选边。
(2)重复以下步骤(n-1)次,使得其他(n-1)个顶点被加入到U中。
①从候选边中挑选权值最小的边加入TE,设该边在V-U中的顶点是k,将k加入U中;
②考查当前V-U中的所有顶点j,修改候选边,若(k,j)的权值小于原来和顶点j关联的候选边,则用(k,i)取代后者作为候选边.
如下图所示的带权连通图,假设起始点为顶点0,采用Prim算法构造最小生成树
(1)首先的最小生成树T仅包含所有的顶点
(2) U={0},V-U={1,2,3,4,5,6},在这两个顶点集之间选择第1条最小边(0,5)添加到T中
(3) U={0, 5},V-U={1,2,3,4,6},在这两个顶点集之间选择第2条最小边(5,4)添加到T中
(4)依此类推,中间步骤下图所示,直到U中包含所"权连通图 有的顶点,这样一共选择了6条边,产生的最小生成树如下图所示

2.实现Prim算法的2个辅助数组是什么?其作用是什么?Prim算法代码。
考虑V-U集合的顶点(因为两个顶点集之间的边是无向边),建立两个数组closest和lowcost,用于记录V-U中顶点j到U中顶点的最小边。

void Peim(MGraph g, int v)
{
	int lowcost[MAXV];
	int min;
	int closest[MAXV];
	int i, j, k;
	for (i = 0; i < g.n; i++)
	{
		lowcost[i] = g.edges[v][i];//置初值,放入顶点v和所有顶带你的权值
		closest[i] = v;
	}
	for (i = 1; i < g.n; i++)//n-1条边,进行n-1次
	{
		min = INF;
		for (j = 0; j < g.n; j++)//遍历找到权值最小的
		{
			if (lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];
				k = j;//记录下标
			}
		}
		lowcost[k] = 0;//lowcost为0表示该顶点已使用
		for (j = 0; i < g.n; j++)//遍历所有顶点,比较找到的顶点与其他顶点的权值是否比原来小
		{
			if (lowcsost[j] != 0 && g.edges[k][j] < lowcost[j])
			{
				lowcost[j] = g.edges[k][j];
				closest[j] = k;//改变权值和相邻的顶点
			}
		}
	}
}

3.分析Prim算法时间复杂度,适用什么图结构,为什么?
时间复杂的为O(n的平方),其适用于边数较多的稠密图,其是通过比较边来找顶点,每次遍历找到一个顶点,与顶点个数无关。适用于邻接矩阵,需要调用到权值,找到特定顶点间的权值。

1.3.2 Kruskal算法求解最小生成树

1.求Kruskal算法生成的最小生成树的边序列
克鲁斯卡尔(Kruskal)算法是一种按权值的递增次序选择合适的边来构造最小生成树的方法。假设G=(V,E)是一个具有n个顶点的带权连通无向图,T=(U,TE)是G的最小生成树,则构造最小生成树的步骤如下:
(1)置U的初值为V(即包含有G中的全部顶点),TE的初值为空集(即图T中的每个顶点都构成一个分量)。
(2)将图G中的边按权值从小到大的顺序依次选取,若选取的边未使生成树T形成回路,则加入TE,否则舍弃,直到TE中包含(n-1)条边为止。
对于下图所示的带权连通图,采用Kruskal算法构造最小生成树的过程如下:
(1)将所有边按权值递增排序,其结果如图所示。图中边上的数字表示该边是第几小的边,如1表示是最小的边,2表示是第2小的边,依此类推。
(2)首先的最小生成树T仅包含所有的顶点,如下图所示
(3)选取最小边(0,5)直接加入到T中,此时不会出现回路,如下图所示。
(4)选取第2小的边(2,3)直接加入到T中,此时不会出现回路,如下图所示。
说明:在采用Kruskal算法构造最小生成树时,前面的两条边可以直接加入到T中,因为只有两条边的图不可能存在回路。
(5)选取第3小的边(1,6),加人到T中不会出现回路,将其加人,如下图所示。
(6)选取第4小的边(1,2),加入到T中不会出现回路,将其加入,如下图所示。
(7)选取第5小的边(3,6),加入到T中会出现回路,舍弃它。选取第6小的边(3,4),加入到T中不会出现回路,将其加入,如下图所示。
(8)选取第7小的边(4,6),加入到T中会出现回路,舍弃它。选取第8小的边(4,5).

2.实现Kruskal算法的辅助数据结构是什么?其作用是什么?Kruskal算法代码。
辅助数组vest用于记录起始点和终止点的下标,通过改变数组的值来改变顶点的所属集合。
代码如下:

typedef struct {
	int u;//起始点
	int v;//终止点
	int w;//权值
}Edge;
void Kruskal(MatGraph g)
{
	int i, j, ul, vl, sn1, sn2, k;
	int vest[MAXV];
	Edge E[MaxSize];
	k = 0;
	for (i = 0; i <= g.n; i++)
	{
		for (j = 0; j <= i; j++)
		{
			if (g.edges[i][j] != 0 && e.edges[i][j] != INF)//存放数据
			{
				E[k].u = i;
				E[k].v = j;
				E[k].w = g.edges[i][j];
				k++;
			}
		}
	}
	InserSort(E, g, e);//插入数据按权值大小排序
	for (i = 0; i < g.n; i++)//初始化vest
	{
		vest[i] = i;
	}
	k = 1;//边的个数
	j = 0;
	while (k < g.n)
	{
		ul = E[j].u; vl = E[j].v;//记录起始点和终止点
		sn1 = vest[ul];
		sn2 = vest[vl];//获取顶点所在编号
		if (sn1 != sn2)//为不同集合
		{
			k++;
			for (i = 0; i < g.n; i++)
			{
				if (vest[i] == sn2)//集合统一编号
				{
					vest[i] = sn1;
				}
			}
			j++;
		}
	}
}

3.分析Kruskal算法时间复杂度,适用什么图结构,为什么?
时间复杂的为O(elog2e),由于其与n无关,只与e有关,适用于稀疏图。
适用于邻接表遍历找到两点之间的权值,邻接表的遍历更加方便找到某点与其有连通的关系并比较权值。

1.4 最短路径

1.4.1 Dijkstra算法求解最短路径

1.基于上述图结构,求解某个顶点到其他顶点最短路径。(结合dist数组、path数组求解)

2.Dijkstra算法需要哪些辅助数据结构
dist[]和path[]。dist[j]表示源点v到j的最短路径长度,path[j]表示源点v到j的最短路经上的与j相邻的一个点的位置。
3.Dijkstra算法如何解决贪心算法无法求最优解问题?展示算法中解决的代码。
通过修正最短路径来解决贪心算法无法求最优解问题。
代码如下:

void Djkstra(MatGraph g, int v)//Dijkstra算法
{
	int dist[MAXV], path[MAXV];
	int S[MAXV];                //S[i]=1表示顶点i在S中,S[]=0表示顶点i在U中
	int MINdis, i, j, u;
	for (i = 0; i < g.n; i++)
	{
		dist[i] = g.edges[v][i]; //距离初始化S[i]=0;
		S[i] = 0;//S[]置空
		if (g.edges[v][] < INF) //路径初始化
			path[i] = v;//顶点v到顶点i有边时,置顶点i的前一个顶点为v
		else
			path[i] = -1;//顶点v到顶点i没边时,置顶点i的前一个顶点为一1
		S[U] = 1; path[v] = 0;//源点编号v放入S中
		for (i = 0; i < g.n - 1; i++) //循环直到所有顶点的最短路径都求出
		{
			MINdis = INF;//MINdis置最大长度初值

			for (j = 0; j < g.n; j++)//选取不在S中(即U中)且具有最小最短路径长度的顶点u
				if (S[j] == 0 && dist[j] < MINdis)
				{
					u = j;
					MINdis = dist[j];
				}
			s[u] = 1;//顶点u加入S中
			for (j = 0; j < g.n; j++)//修改不在S中(即U中)的顶点的最短路径
				if (S[j] == 0)
					if (g.edges[u][j] < INF && dist[u] + g.edges[u][i] < dist[j])
					{
						dist[i] = dist[u] + g.edges[u]G] path[i] = u;
					}
		}
	}
}

4.Dijkstra算法的时间复杂度,使用什么图结构,为什么。
Dijkstra算法的时间复杂度为O(n^2) ,其中n为图中顶点的个数。邻接矩阵。
邻接矩阵方便通过下标找到顶点间权值并在数组中改变,若为邻接表则较难找到权值。

1.4.2 Floyd算法求解最短路径

代码如下:

void Floyd(MatGraph g)//Floyd算法
{
	int A[MAXV][MAXV], path[MAXV][MAXV];
	int i, j, k;
	for (i = 0; i < g.n; i++)
		for (j = 0; j < g.n; j++)
			A[i][j] = g.edges[i][j];
	if (i != j && g.edges[i][j] < INF)
		path[i][i] = i;//顶点i到j有边时
	else
		path[i][i] = -1;//顶点i到j没有边时
	{
		for (k = 0; k < g.n; k++)//依次考查所有顶点
		{
			for (i = 0; i < g.n; i++)
				for (j = 0; j < g.n; j++)
					if (A[i][j] > A[j][k] + A[k][i])
					{
						A[D[] = A[i][K] + A[k][i]; //修改最短路径长度
						path[i][] = path[K][i];	   //修改最短路径
					}
		}
	}
}

1.Floyd算法解决什么问题?
可以通过以每个顶点作为源点循环求出每对顶点之间的最短路径。除此之外,弗洛伊德算法也可用于求两顶点之间的最短路径。
2.Floyd算法需要哪些辅助数据结构
假设有向图G=(V,E)采用邻接矩阵g表示,另外设置一个二维数组A用于存放当前顶点之间的最短路径长度,即分量A[i[j]表示当前ij的最短路径长度。
初始时尚未考查任何顶点,若i到j有边<i,j>,将该边看成是i到j的最短路径,该路径上顶点j的前一个顶点是i,所以置path-1[i][j]=i,否则path-1[i][i]=-1(表示无路径)。
3.Floyd算法优势,举例说明。
Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行V次 Dijkstra算法。
最短路径的其他算法
SPFA算法\Bellman-Ford算法、Johnson算法、A*算法

1.5 拓扑排序

1.找一个有向图,并求其对要的拓扑排序序列

由图可得此拓扑排序的拓扑代码为1->3->2->4->7->6->5.当然,拓扑排序的方法不止一种。
2.实现拓扑排序代码,结构体如何设计?
为了实现拓扑排序的算法,对于给定的有向图,采用邻接表作为存储结构,为每个顶点设立一个链表,每个链表有一个表头结点,这些表头结点构成一个数组,表头结点中增加一个存放顶点入度的域count,即将邻接表定义中的VNode类型修改如下:
typedef struct
{
Vertex data;//顶点信息
int count;//增加数据域:存放顶点入度
ArcNode firstarc;//指向第一个邻接点
}VNode;//头结点类型
3.书写拓扑排序伪代码,介绍拓扑排序如何删除入度为0的结点?
伪代码:
遍历邻接表
计算每个顶点的入度,存入头结点count成员
遍历图顶点
若发现入度为0顶点,入栈st
while(栈不空)
{
出栈节点v,访问。
遍历v的所有邻接点
{
1所有邻接点的入度-1
若有邻接点入度为0,则入栈st
}
}
在执行拓扑排序的过程中,当某个顶点的入度为零(没有前驱顶点)时,就将此顶点输出,同时将该顶点的所有后继顶点的入度减1,为了避免重复检测入度为零的顶点,设立一个栈St,以存放入度为零的顶点。
4.如何用拓扑排序代码检查一个有向图是否有环路?
对于无环的有向图,对其进行拓扑排序可输出其所有顶点,而有环的图则不行。

1.6 关键路径

1.什么叫AOE-网?
若用前面介绍过的有向无环图(directed acycline graph, DAG)描述工程的预计进度,以顶点表示事件,有向边表示活动,边e的权c(e)表示完成活动e所需的时间(如天数),或者说活动e持续时间。图中入度为0的顶视斯讲解点表示工程的开始事件(如开工仪式),出度为0的顶点表示工程结束事件,称这样的有向图为边表示活动的网(activity on edge network, AOE网)。
2.什么是关键路径概念?
假设事件 是源点、事件y是汇点,并规定事件x的发生时间为0。定义图中任一事件v的最早(event early)开始时间ve(z)等于x到所有路径长度的最大值,完成整个工程所需的最少时间等于汇点y的最早开始时间ve(y)。源点x到汇点y的最长路径就是关键路径,完成工程所需最少时间就是关键路径的长度。
3.什么是关键活动?
在AOE网中,从源点到汇点的所有路径中具有最大路径长度的路径称为关键路径。完成整个工程的最短时间就是AOE网中关键路径的长度,或者说是AOE网中一条关键路径上各活动持续时间的总和,把关键路径上的活动称为关键活动。关键活动不存在富余的时间,而非关键活动可能存在富余的时间。通常一个AOE网可能存在多条关键路径,但它们的长度是相同的。

2.PTA实验作业

2.1 六度空间

2.1.1 伪代码

int main(void)
{
	//给snap分配空间
	//动态分配内存存在失败的可能,所以在进行动态分配内存后应该进行对应的指针是否为空指针的判
	//向图输入数据
	//引用广度搜索函数,输出
	//直接进行头指针的内存释放不全等于所有指针内存的释放 
	//free(snap);
}
int BFS//广度遍历函数
{//       队列      遍历登记       队头  队尾  计数器 层数
	int q[MAX], visit[MAX], front, rear, count, level, last, tail, v, j;
	for (j = 0; j < 10001; j++)//初始化数组 
		visit[j] = 0;
	visit[i] = 1;//开始结点 
	front = rear = -1;//队列初始化 
	count = 1;//计算六度空间的个数
	level = 0;//level计算层数,等于6时跳出
	last = i;//last为上一层最后的顶点
	q[++rear] = i;//入队 当前顶点所在层数
	while (front < rear) //遍历队列(六层以内) 
	{
		//出队 
		for (j = 1; j <= N; j++)//遍历 
			if (!visit[j] && snap[v][j] == 1)
			{//当结点没有记录而且此处结点为顶点时 
				//入队列 
				//记录对应位置 
				//计数器+1 
				//tail是当前层的最后一个顶点
			}
		if (v == last)
		{
			//层数加一 
			//记录最后一个顶点 
		}
		if (6 == level)//等于六层时,退出循环 
			break;
	}
	//返回六度空间内所有顶点数
}

2.1.2 提交列表

2.1.3 本题知识点

*解题思想:
*对图进行广度搜索
*得出每层中的顶点数
*计算百分比

*图的广度搜索原理解析:
*类似二叉树的层序遍历
*1、从所需要的顶点进入图(类似利用此顶点为树的根结点,构建一棵树)
*2、根结点入队列
*3、寻找与此顶点相连的所有顶点并放入队列中(图的临接矩阵中,储存的是每个顶点间的边的关系,而且无向图的临接矩阵一定为对称矩阵)
*4、当顶点所在行遍历结束,取出队列的下一个顶点,重复。直至遍历所有的顶点

2.2 村村通或通信网络设计或旅游规划

2.2.1 伪代码

int main()
{
	//输入村庄数,边数
	HVV();//输入数据并排序
	cout << Lowcost() << flush;//计算最小并输出
}
void HVV()
{
	int i, a, b, c;//ab分别为两个村庄,c为价钱
	for (i = 0; i < M; i++) {//循环m次把边的两个顶点和价钱都存进去
		//输入村庄编号和价钱
	}
	sort(X, X + M, BJ);//排序,sort函数可以去网上搜,大概意思是将整个范围进行排序,排序的范围为参数一到参数二,第三个参数是一个说明比较规则的函数,函数中的比较内容就是比较的规则。
}
int Lowcost()
{
	int x[1001] = { 0 };//定义visit
	int sum = 0;//记录最低费用
	//把最小的路径的两个点都标记
    //sum+=该路径权值
	for (i = 2; i < N; i++)
	{
		for (j = 1; j < M; j++)
		{
			//如果一个点标记一个点没标记 ,sum加上权值退出  				
		}
		if (j == M)//说明全都遍历完没有路
	}
	return sum;
}
bool BJ(Road m, Road n) {//比较函数
	//对每一段路的价值进行比较,从小往大排	
}

2.2.2 提交列表

2.2.3 本题知识点

sort(X, X + M, BJ);//排序,sort函数可以去网上搜,大概意思是将整个范围进行排序,排序的范围为参数一到参数二,第三个参数是一个说明比较规则的函数,函数中的比较内容就是比较的规则。

posted @ 2021-05-23 21:10  51456  阅读(446)  评论(0编辑  收藏  举报