DS作业06-图
1.本周学习总结(0--2分)
1.1思维导图
1.2谈谈你对图结构的认识及学习体会。
图这一章的学习,是经过树学习后,难得一章重新寻找到感觉的学习。因为这一章比较少用递归,使用的是结构体,很多东西我有基础。所以学起来快很多,而且感觉也很熟悉,有一种似曾相识的感觉。图的结构主要靠2个变量,边和顶点数。这2个变量串起来组成的2中方法:邻接表和邻接矩阵。结构上还是学过的链表和2维数组,所以学起来还是比较顺利。两种不同的存储有各自的优缺点,适用不同的题目。虽然在变成题目代码的实现上还是有难度,但是还是思路想得到。比如pta的好几道编程题,我直接参考数组的写法,跳过了图的写法。如果用图,会复杂点,但是就是增加一步建图的过程,其余的思路都是一样。结构体的定义上不管邻接矩阵还是邻接表都是比较容易。这一章的学习,总体上感觉不错,以前很长一段时间都被树搞的很迷,终于找到点感觉。当然了这一章也是有难度的,难在一些有名的算法的实现。比如基本的一些寻找路径的算法,Dijkstra和Floyd算法,虽然Floyd算法更精短,一些深度,广度遍历的算法,这些算法背下来,能用就行。思路都了解,大体上不会很难,都会使用。
2.PTA实验作业(6分)
2.1.题目1:题目名称
2.1.1设计思路(伪代码)
宏定义无穷大INF为32767
宏定义 MAXV 为1001
宏定义邻接矩阵 g[MAXV][MAXV]/数组 visited[MAXV]={0};
定义 count 为1来判断是否为连通图
Main:
{
定义 i,n,e分别表示循环变量、顶点数、边数 /定义浮点型数据 sum为修路成本
输入 n,e 顶点数 边数
if n-1大于e then //不能够建成图
cout<<-1
return 0
CreateGraph(n, e)//建邻接矩阵
sum=Prim(n,1)//调用prim函数返回sum
if count==n then //说明图连通
cout<<sum
else
输出-1
end if
return 0
}
void CreateGraph//建邻接矩阵
{
定义 i,j循环变量
定义 a, b, c;分别对应两个城镇的编号以及该道路改建的预算成本
for i = 0 to n //初始化邻接矩阵
for j = 0 to n do
g[i][j]==0
end for
end for
for i = 1 to e do//赋值矩阵
输入 a,b,c
g[a][b] =g[b][a]= c;
end for
}
int Prim//计算最小值
{
定义i, j表示循环变量
定义min为最低的费用,index用来存小路径下标
定义 数组 lowcost[MAXV],close[MAXV],
定义 cost = 0表示最低成本,
for i = 1 to n //给2个数组置初值
lowcost[i] = g[v][i];
close[i] = v;
end for
for i = 1 to n
min = INF
定义 flag=0//用来判断这个费用是否符合最低费用要求,如果符合计算进去
for j = 1 to n //从剩下的城市中找最近的点
if lowcost[j] 不等于 0且lowcost[j] 小于 min) then //寻找最少费用
min = lowcost[j];
index = j;
flag=1;
end if
end for
if flag不为0 then //该费用符合题意
cost += min;//加入cost
count++;
lowcost[index] = 0;//记录这个结点访问过
for j=1to n do //调整最短路径,最少费用
if lowcost[j] 不等于 0且g[index][j]小于lowcost[j then//修改最少费用
lowcost[j] = g[index][j];
close[j] = index
end for
end for
return cost//返回费用
}
2.1.2代码截图
2.1.3本题PTA提交列表说明。
+Q1: 第一个提交是没有考虑到边和顶点数不符合关系,这个时候不能够建成功矩阵。
+A1:在主函数判断的时候增加:
+Q2:没有判断连通不连通,万一图是不连通的情况下,也不符合题目要求。
+A2:百度了一个方法,初始化一个
count:
变量用来记录成功的顶点数。如果遍历完成后成功的顶点数和初始n相同,说明每一个顶点都遍历到了,这是一个连通图。否则不符合。
+Q3:25分后最大N这里过不去,不知道怎么解决了。
2.2 题目2
2.2.1设计思路(伪代码)
定义vector和set容器
定义v,e,k,分别是无向图的顶点数、边数、以及颜色数。
定义num是组别的个数
定义动态数组mp;
输入各顶点之间的关系,类似于建邻接矩阵
for i=0 to e
依次输入e个组数据
打入动态数组mp中//输入成有向图这种情况
end for
输入num组判断颜色的个数
do while
flag初始化为1
每次循环都将容器 s 清空
for int i = 1 to v
输入各点对应涂的颜色,并且将颜色输入容器 s 中//相同颜色只需要记录一次
end for
if 容器 s 大小不等于颜色总数k then flag=0该方案不行
for int i = 1 to v//遍历每个节点
for int j = 0 to mp[i].size()// 遍历与该节点相邻的节点
if 两相邻节点颜色相同 then 不符合涂色方案,跳出循环
end for
if flag=0 then 跳出循环//不合法
end for
if(flag=1) then 输出符合方案
else 输出不符合
end while
2.2.2代码截图
2.2.3本题PTA提交列表说明。
+Q1:第一次容器内的数循环没有清空,导致只能过一个测试点。
+A1:在循环开始前加入:
+Q2:一开始不知道如何判断颜色是否合理,不知道怎么判断。
+A2:百度一下,百度是把用过顶点的颜色信息存在数组里面,类似哈希数组的方法,这一遍历这个数组就知道这个颜色使用过没,是否符合题意。
2.3 题目3
2.3.1设计思路(伪代码)
定义邻接矩阵g[10001][10001],
定义顶点数v,边数e,循环变量i,
定义变量x,y用来存放结点关系数据
main:
{
定义浮点型数据 n,m来求最后所占比率
输入顶点数v和边数e
while e-- //构建邻接矩阵
输入边关系 x y
g[x][y] = g[y][x] = 1
end while
for i=1 to v
定义浮点型数据 n,m//记录比率
n=v
m=bfs(i) //调用bfs函数
end for
return 0
}
bfs(int z)//广度遍历
{
定义数组vis[10001]=0 记录被访问过的结点
last = z表示记录每层的最后一个元素
tail表示用于记录每一层压入栈时的结点
定义 level = 0 用于判断距离是否合题意为6
定义count=1//记录符合的结点数目
建int型栈q
z入栈
将vis[z]置为1//访问成功标记
while q不为空
z = q.front()//取栈顶元素z
q.pop()//使用过的元素去掉
for i = 1to v //广度遍历
if g[z][i] 等于1 && vis[i]等于 0 then//符合题意
count++;
vis[i] = 1;
q.push(i);
tail = i;
end if
end for
if last 等于z then////这一层全部弹出,准备开始下一层,当前层最后一个元素(last) 记录下来 level++;
last = tail;//记录最后一个元素
end if
if level 等于 6 break //符合题意距离6,跳出循环
end while
return count//返回符合的结点数
}
2.3.2代码截图
2.3.3本题PTA提交列表说明。
+Q1:记录2个比例的时候未使用浮点数,导致结果有误差,没有按题目输出要求输出。
+A1:改成double定义数后输出结果格式正确了。
+Q2:一开始不知道怎么处理距离为6这个问题,使用了深度遍历,查到了到就结束程序,不能够多重方向寻找
+A2:改成广度遍历,加上vis数组判断,这样所有结点都能够访问一遍,所有点都不会漏掉。
+Q3:重新寻找一层的时候没有记住上一层最后一个结点,倒是寻找重复了,
+A3:用last更新上一层的最后一个结点,保证寻找的时候不会重新走老路,记录的都是新的结点。
3、上机考试错题及处理办法(-2--2分)
3.1截图错题代码
3.1.1:题目
3.1.2:代码
3.1.3 错的原因及处理方法
+原因:这个格式错误我一开始没想到是输出的问题,因为我只试了bfs函数,发现没问题,结果试了dfs函数发现少了空格,才知道是flag的问题,这里的flag是个全局变量,忘记更改他的值了,结果成这样:
+更改方法:在flag输出了第一个非空后把flag变为1,这样后面的空格就可以出来了。
3.2.1题目
3.2.2代码
3.2.3错的原因及处理办法
+原因:遍历循环查找结点的时候指针忘记移动:少了p=p->nextarc,这一步:
+处理方法:
+原因:输出的时候掉了第一个数据:
+处理方法:
输出的时候这里有问题:
这里flag判断一下直接把第一个数跳过了,flag的作用用来判断输出空的,不能够把数字一起输出,改成这样,把他们拆开: