DS博客作业06--图
1.本周学习总结
1.1思维导图
1.2学习体会
- 学习内容:图的学习内容非常多,有邻接矩阵和邻接表两种图的基本运算代码,代码量真的好大嗷,Prim算法、Kruskal算法、Dijkstra算法等真的不简单,同时延续了树的画图要求,需要掌握图应用的代码同时,也要掌握怎么样构造邻接矩阵,画出邻接图,找出最小路径,真的还是要好好再看看每一趴。
- 学习感受:这一章真的数构学习以来难度排行top,感觉还在树上机考后的浑浑噩噩中,就突然进入图的学习,图的结构体真的很复杂辽,写代码的时候真的很容易漏掉,算法种类比较多,代码量也令人头掉,感觉老师上课的时候重点会放在理论上,我就会有忽略代码上的熟悉,还是没有学进去叭,光是掌握理论以至于pta又开始没有思路辽,这一章一定要好好复习,因为不仅仅是图的知识点,更是和之前队列等知识点的结合,很重要!
2.PTA实验作业
题目1:图着色
图着色问题是一个著名的NP完全问题。给定无向图G=(V,E),问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?
但本题并不是要你解决这个着色问题,而是对给定的一种颜色分配,请你判断这是否是图着色问题的一个解。
2.1.1设计思路
【整体】——邻接矩阵比较方便简单
- 创建图的邻接矩阵
- 定义visited数组标记颜色是否存在,0为不存在,1为存在
- 定义颜色种类num,flag作为判断方案是否正确,0为正确,1为不正确
- 标记颜色
for i=1 to g.v
输入颜色种类
if 颜色不存在
num++
visited[]=1;
end if
end for
- if num != 输入的k种
flag=1
- 遍历每个顶点
if 顶点构成边&&颜色相同
flag=1;退出循环
- 判断正误
if flag==1
输出No
else
输出Yes
2.1.2代码截图
2.1.3本题PTA提交列表说明。
说明:开始看到多种错误的时候真的是懵了。。。。。
bug1——段错误:题目里面提到顶点数最大为500,我直接在数组上设为500size,jio得这样没毛病,但是数组不是从0开始,这样是不够用滴;
bug2——答案错误:遍历所有顶点双层循环时,i和j应该都从1到n这样能够完全遍历,一直都没有发现Yes和No不是所有大小写,晕
2.2 题目2:六度空间
六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”如图所示。
六度空间”理论虽然得到广泛的认同,并且正在得到越来越多的应用。但是数十年来,试图验证这个理论始终是许多社会学家努力追求的目标。然而由于历史的原因,这样的研究具有太大的局限性和困难。随着当代人的联络主要依赖于电话、短信、微信以及因特网上即时通信等工具,能够体现社交网络关系的一手数据已经逐渐使得“六度空间”理论的验证成为可能。
假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。
-
输入格式:
输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤10,4,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N号)。 -
输出格式:
对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。
2.2.1设计思路
#创建图的邻接矩阵
- 定义visited数组判断顶点是否被访问过
#广度遍历图
- 定义num计算符合的节点数,c=6
- 建立两个队列q1,q2
- 结点存入q1
- while c-- //符号六度空间要求
while q1不空
q1队首进入q2
q1.pop()
end while
while q2不空
遍历顶点
for i=1 to n
if edge[q2.front()][i]==1 && 未遍历过
visited[i]=1;进队;num++;
end for
q2.pop()
end while
end while
- 输出百分比
2.2.2代码截图
2.2.3本题PTA提交列表说明。
说明:
一直没有看懂这道六度空间应该怎么做,一是不太理解六度空间到底应该是什么概念,二是不知道该怎么用代码实现这一理论,就借鉴了一下室友的代码,明白了这道题应该是分别遍历每个顶点,记录与顶点距离不超过6的其他点,求出其占比,所以采用广度遍历,分别输出每个点符合“六度空间”理论的结点比。自己写的时候就完全没有思路,偷了懒以为看了室友的代码就完全懂了,结果上机考的时候还是在两个栈上面迷迷糊糊,所以还是得自己写!
2.3 题目3:公路村村通
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
-
输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。 -
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。
2.3.1设计思路
【整体】——Prim算法
#创建邻接矩阵,边权值先初始化为INF
【Prim算法】
#定义lowcost数组标记是否被访问过,min表示最低预算,cost表示最低成本
#lowcost数组赋初值
for i=1 to n
lowcost[i] = edge[v][i] //v从1开始
end for
#遍历所有顶点
- 最小预算min初始化为INF
- if 顶点未被访问 && 图是连通的
最低预算为该边权值
记录最近顶点编号k
end if
- if min == INF //图不连通
return -1
end if
- 累加最低成本
- k顶点标记已访问
- 修改数组lowcost
2.3.2代码截图
2.3.3本题PTA提交列表说明。
说明:
- bug1:主函数中的输入写成了 cin>>v,n 检查了很久都没有发现,导致一开始一直无法正常输入
- bug2:遍历过程中累计最低成本,括号过多一时疏忽,把Prim函数返回结果放到了遍历中,导致遍历完第一个结点函数结束了
- 总结:还是过于疏忽,保证输入正确很重要,而且每次有bug好像都不能知道具体是什么错误,这样就会导致上机考写题很慢而且上机考出现bug也不能轻易找到错误,还是代码的逻辑性不强
3、图上机考试
3.1 错题一:最短路径
3.1.1错题代码截图
这道题由于没有在练习集出现,对Dijkstra算法不太熟悉,就没有做,没法儿贴代码,就写一下设计思路叭
【Dijkstra算法】
- 定义dist数组--记录顶点到其他顶点的权值、path数组--记录与顶点有边的前一个顶点、S数组--储存最小路径长度的顶点
- 初始化三个数组,源点编号进入S
- 遍历所有顶点,求出所有顶点的最短路径
for i=0 to g.n
Min=INF
for j=0 to g.n
if 不在S中&&有最小最短路径
记录顶点u
Min=dist[j]
end for
顶点u进入S
修改不在S中的最短路径
- 输出最短路径
后续改进
3.2 错题二:拓扑序列
3.2.1错题代码截图
3.2.2错误原因&&后续改进
- 入度初始化for循环写成了 从1到n-1 应该改成 从0到n
- 遍历顶点,设置每个点的入度时应该是G->adjlist[p->adjvex].count++,而不是G->adjlist[i].count++;
- 应该用data数组存储拓扑序列,在写的时候没有储存拓扑序列,第一个结点存入数组后,应该出栈;
- 在前一个结点进入数组后,相应的结点应该是G->adjlist[p->adjvex]入度减少,而不是G->adjlist[p->nextarc].count
- 对于是否是环路的判断,累计进入数组的结点数num++放的位置不对,导致无法判断是否有环,可以直接根据data数组的最后元素数+1与顶点数进行比较
总结
- 这道题主要错误还是在对于数组的初始化和遍历的范围不明白从0或1开始的区别,
- 邻接表上对于邻接表的结构体元素不熟悉,对于所对于的意义不熟练,这些要注意!
3.3 错题三:六度空间
3.3.1错题代码截图
3.3.2错误原因&&后续改进
- 数组最大值设为100太小了,导致段错误,应该改为10000
- 广度遍历不应该从1到e,而是应该从1到n
- 要求的输出格式无
总结
- 注意数组最大值不宜过大也不宜过小,容易导致段错误
- 看清输出格式,本来这道题可以拿分滴,很可惜,都是一些很简单的错误
3.4 错题四:公路村通
3.4.1错题代码截图
3.4.2错误原因&&后续改进
- 建图时,边权值初始化应该分情况,对角线上应初始化为0,其他初始化为INF,而不是全部是INF
- 修改lowcost数组时,应该是更改有最小成本对应的顶点k而不是循环变量i
总结
- 这道题主要是没有真正理解应该怎么修改lowcost数组,反而理解为edges数组与lowcost再进行一轮比较,导致只拿了一部分的分
3.5 错题五:天梯地图
本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。
-
输入格式:
输入在第一行给出两个正整数N(2 ≤ N ≤ 500)和M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:V1 V2 one-way length time其中V1和V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1到V2的单行线,则one-way为1,否则为0;length是道路的长度;time是通过该路所需要的时间。最后给出一对起点和终点的编号。 -
输出格式:
首先按下列格式输出最快到达的时间T和用节点编号表示的路线:Time = T: 起点 => 节点1 => ... => 终点然后在下一行按下列格式输出最短距离D和用节点编号表示的路线:Distance = D: 起点 => 节点1 => ... => 终点如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。如果这两条路线是完全一样的,则按下列格式输出:Time = T; Distance = D: 起点 => 节点1 => ... => 终点
3.5.1错题代码截图
这道题不会,没有提交记录,设计思路如下
因为这一部分也是采用DIjkstra算法,第一道题已经介绍过Dijkstra算法了,只是数组名不同,这里就不再重复了,但是存在一点点不同
#difference
【最快路径】
在修改不在S中的最短时间路径时
if 时间一样最短
取最短路径
【最短路径】
在修改不在S中的最短路径时
if 距离一样最短
取最短时间