本章学习了图的结构和基本操作,我觉得这章有两个地方比较难,第一个是图的遍历,第二个是最小生成树的两个算法。两种图的基本操作我都用代码敲了一遍,然而印象最深刻的,却是在PTA上的拯救007的那道题,耗了我挺长一段时间了。
题目如下:
(一)首先读题,分析这题需要的变量。
其中有鳄鱼数目,007的最大跳跃距离,以及每条鳄鱼的坐标。对于鳄鱼数目和007的最大跳跃距离,用两个整型变量定义即可,而对于鳄鱼的坐标,我们需要用结构体变量来打包两个整型变量x,y。另外,我们需要定义一个visited数组,org结构体数组,reach辅助的结构体数组,以及一个rea和urea整型变量。它们的作用会在后面提到。
其中变量和结构体定义如下:
1 typedef struct{ //将坐标打包成结构体Locate 2 int x; 3 int y; 4 }Points[100], Locate; 5 //结构体定义 6 7 8 int N, D;//定义鳄鱼数量和最大跳跃距离 9 int rea, urea;10 bool visited[100];//定义访问标记数组11 Points org;//定义点数组(鳄鱼点坐标数组)12 Points reach;//定义到达数组13 //全局变量定义
(二)确定好变量后,分析跳跃时需要用到的函数。
首先求两点距离的时候,我们需要距离函数Distance(),头文件包含<cmath>,利用sqrt()函数求根号即可。然后考虑到坐标有正负之分,利用abs()函数求绝对值后返回double值得到两点的距离。
然后判断一鳄鱼顶点和org数组的一点之间,007能否跳过,需要利用Reach()函数来进行判断,并且在选择org数组中的点之前,需要判断其之前是否被访问过。被访问过的鳄鱼顶点不能被再次访问。跳跃,函数返回一;反之返回零。
代码如下:
1 double Distance(int x1, int x2, int y1, int y2) { //求距离函数 2 int dx, dy; 3 double distance; 4 5 dx = abs(x2 - x1);//求横坐标的差 6 dy = abs(y2 - y1);//求纵坐标的差 7 distance = sqrt(dx * dx + dy * dy);//开方求距离 8 9 return distance;10 }11 12 bool Reach(int i, Locate com) { //判断能否到达的函数13 int x, y;14 15 x = com.x;16 y = com.y;//获得com点的坐标17 18 if (!visited[i] && Distance(org[i].x, x, org[i].y, y) <= D)//如果两点距离小于等于D,即007可以从一点到达另一点,则返回true;否则返回false19 return true;20 else21 return false;22 }
(三)最后一个函数我想单独分开来写。因为这题的精华都在这里了。首先因为007是分步跳跃的,所以我们不妨先通过一个for循环将所有第一次跳跃可以到达的点,放入reach结构体数组里面,然后rea作计数用。rea代表从起点的已被访问过的结点个数。urea代表从终点的已被访问过的结点个数。
接着取reach数组中的每一个鳄鱼顶点,用Reach函数判断reach数组中的顶点能否到达其他未被访问过的鳄鱼结点......有点像感染传播......直到rea等于urea,此时相当于整个最大连通图都找到了,但是该图的边界都无法到达池子的边界,循环结束,输出no。
最后,while循环这里需要插入一个结束的判断,遍历每一个跳跃后(这里比方说是第一次)能到达的顶点,若在下一次跳跃中(这里是第一次相应的是第二次)能够到达池子边界,则输出“Yes”。
由于两点之间,直线最短。到达边界的条件则为:50 - max(abs(x), abs(y)) <= D ,即取横坐标和纵坐标的绝对值中的最大值,然后加上D后比50大,说明该点可以到达边界。
代码如下,main函数我就不放上来了:
1 int Jump() { //核心函数...BFS 2 for (int i = 0; i < N; i++) { 3 if (Distance(org[i].x, 0, org[i].y, 0) -7.5 <= D) { //统计007从岛上直接能跳到的点并放到reach数组中 4 reach[rea] = org[i];//将能跳到的点信息存在reach数组里面 5 visited[i] = 1;//标记数组置为1 6 ++rea; 7 } 8 } 9 10 while (rea != urea) {11 Locate temp;12 int x, y;13 14 temp = reach[urea];15 ++urea;16 x = temp.x;17 y = temp.y;//获得当前点的x,y坐标18 19 if (50 - max(abs(x), abs(y)) <= D ) { //若当前点可以到达边界,则输出Yes20 cout << "Yes";21 return 0;22 }23 24 for (int j = 0; j < N; j++) {25 if (Reach(j, temp) == true) { //若当前点可以达到其他孤立的点,则将其放到reach数组中26 reach[rea] = org[j];27 ++rea;28 visited[j] = 1;//visited数组置129 }30 }31 }32 33 cout << "No";//找不到任何一个点可以到达边界,输出No34 return 0;35 }
做完之后,感觉思路也清晰多了。题的实质是找到权值有条件限制的最大连通图是否能到达边界的问题,不过解决这道题确实耗了不少时间....
上一阶段的学习中,花了较多的时间来打代码,弥补了上上阶段学习中的一些遗憾,但是网安实验室的进度似乎停滞了。总之下一阶段得安排好自己的时间,不然到实验室得挨打啊。
加油吧!不要辜负了一年前的自己。