1.思维导图及学习体会
1思维导图
2.谈谈你对图结构的认识及学习体会
- 1. 在我看来,图就是一堆顶点和边的集合,既然是图可以分为有向图和无向图、还可以分为连通图和非连通图。在图结构中,每个元素可以有零个或多个前驱元素,也可以有零个或多个后继元素,也就是说元素之间的关系是多对多的。图的存储方法有邻接矩阵和邻接表,邻接矩阵顾名思义,是一个矩阵,存储着边的信息的矩阵,而顶点则用矩阵的下标表示,如果是无向图则有A [j ,i] = A[i, j],所以无向图的邻接矩阵是一个对称矩阵;但如果是有向图,则不一定是一个对称矩阵。邻接表可以有效避免内存的浪费,邻接表用一个一维数组存储顶点,利用邻接表建图时候,需要创建多个结构体,如结点类型的结构体,头结点也弄一个结构体,还有邻接表一个结构体。两种不同的存储有各自的优缺点,适用于不同的地方。如果是稀疏图或者需要特定用途的话采用领阶矩阵存储结构的好,反之如果是需要插入删除等操作的话采用邻接表的好。
- 2.图的遍历有广度优先遍历BFS和深度优先遍历DFS,不过书上给两种算法的代码对应的都是针对于连通图的算法,还有最小生成树的算法有prim算法和克鲁斯卡尔算法,克鲁斯卡尔算法的时间复杂度与边e有关,克鲁斯卡尔算法时间复杂度O(e^2),prim算法时间复杂度与图的顶点n数有关,其时间复杂度为O(n^2)。还有求最短路径的算法:Dijkstra和Floyd算法,虽然Floyd算法更精短,但真是理解不来,时间复杂度也不少O(n^3),按老师所说的还算不错了。
- 3.图的话结构体多了很多,光是要记住的类型名也很多,因为结构体多,所以有时候在调用一些结构体里的数据时就容易搞错,也因为Devc有时候不能够像vs那样直接显示结构体里包含的成员,所以这段时间也改用vs来编写代码了,这次pta上的题目大都可以看书本上的代码来写,或改进些
2.PTA实验作业
2.1.题目1:7-3 六度空间
“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”如图1所示。
“六度空间”理论虽然得到广泛的认同,并且正在得到越来越多的应用。但是数十年来,试图验证这个理论始终是许多社会学家努力追求的目标。然而由于历史的原因,这样的研究具有太大的局限性和困难。随着当代人的联络主要依赖于电话、短信、微信以及因特网上即时通信等工具,能够体现社交网络关系的一手数据已经逐渐使得“六度空间”理论的验证成为可能。
假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。
2.1.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 do
n=v
m=bfs(i) //调用bfs函数
end for
return 0
int bfs(int z)
定义数组vis[10001]=0 表示是否被访问过的结点
定义 last = z表示记录每层的最后一个元素
i定义tail表示用于记录每一层压入栈时的结点
定义 level = 0 表示与该结点距离是否为6
定义count=1//表示结点
创建int型栈q并入栈z
将vis[z]置为1表示访问过了
while q不为空
z = q.front()//取栈顶元素于z
q.pop()//去栈顶
for i = 1to v do //广度遍历方法
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 //符合题意的路径节点
return count
2.1.2代码截图
2.1.3本题PTA提交列表说明。
- Q1:起初以为这是深度遍历问题,想的是与这个结点距离为6,那么便从起点出发,一旦找到长度6的顶点便返回
- A1:然后试了好几次测试样例都是错的,问了舍友才知道应该用广度遍历,广度遍历的话找与起点有联系的点,并以此扩散,这样可以找到全部符合题意的点,而不是像深度遍历一样只能找一路
- Q2:知道深度遍历行不通,就将函数题的邻接矩阵广度遍历拿来用,再慢慢改动点
- A2:基本就是重写代码了,一堆宏定义都是是舍友教的,从编译错误那里开始就改成了广度遍历法
- Q3:提交pta,发现还是不对,输出出来的结果比起答案少很多
- A3:在遍历中,我没有对一旦level等于6就退出循环,导致最后结果比起来少了很多
2.2.题目1:7-4 公路村村通
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
2.2.1设计思路(伪代码)
宏定义无穷大INF为32767 及 MAXV 为1001
宏定义邻接矩阵 g[MAXV][MAXV]以及数组 visited[MAXV]={0};
定义 count 为1来判断是否为符合要求
int main()
{
定义 i,n,e分别表示循环变量、顶点数、边数
定义浮点型数据 sum为成本
输入 n,e //顶点数 边数
if n-1大于e then //不符合的情况
输出-1
return 0
end if
CreateGraph(n, e)//建图函数
sum=Prim(n,1)//计算最低成本 调用prim函数
if count==n then
输出sum
else 输出-1
end if
return 0
}
void CreateGraph(int n, int e) //创建邻接矩阵
{
定义 i,j,a, b, c;
for i = 0 to n; do//初始化
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(int n, int v)
{
定义 数组 lowcost[MAXV],close[MAXV], cost = 0表示最低成本, i, j表示循环变量 min为最低的费用,index用来存下标
for i = 1 to n //给lowcost数组和close数组置初值
lowcost[i] = g[v][i];
close[i] = v;
end for
for i = 1 to n do
min = INF
定义 flag=0//用来判断这一层是否有最低费用
for j = 1to 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;
count++;
end if
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 if
end for
end for
return cost;
}
2.2.2代码截图
2.2.3本题PTA提交列表说明。
- Q1:如果无法畅通的情况处理不来
- A1:后来在每次循环时候将最小min等于无穷大INF,如果最小的路径等于无穷大,则说明没有路径即无法正常畅通。
- Q2:一开始是看书上的prim算法写的,没怎么改动,主要是那个最低费用的一开始不知道怎么写,然后先试着提交一下还是有分的
- A2:后来我就设了min和index分别来存最少的路费和对应的点,并通过最后求一行的cost来计算最低费用
- Q3:最后在第一层循环内有个地方错误
- A3:就是要在每次要将index所在第一行初始化,就是lowcost[index]要置为0,否则会错误,不能跳进循环
2.3.题目1:7-1 图着色问题
图着色问题是一个著名的NP完全问题。给定无向图G=(V,E),问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?
但本题并不是要你解决这个着色问题,而是对给定的一种颜色分配,请你判断这是否是图着色问题的一个解。
2.3.1设计思路(伪代码)
宏定义数组 visited[501]={0},d[501],k=0
宏定义邻接矩阵a[501][501]及循环变量与一些变量:v,e,z,x,y,i,j,n;
void dfs(int i)
{
定义 j;
d[k++]=i;
visited[i]=1;
forj=1to v do
if(a[i][j]等于1 并且 visited[j]等于0 then dfs(j);
end if
end for
}
void dfs1()
{
定义 i;
for i=1 to v
if visited[i]等于0 then dfs(i); //没被访问过
end for
}
int main()
{
输入v、e、z;
for i=0 to e
输入变关系x、y;
a[x][y]=a[y][x]=1;
end for
dfs1();
输入n;
while n--
初始化 b[501]={0},c[501],e[501],sum=0,flag=1;
for i=1 to v;i++)
输入c[i];
b[c[i]]++;
if b[c[i]]等于1 then sum++;
end for
if sum不等于z then flag=0;
end if
for i=0 to k do e[i]=c[d[i]]
end for
for i=0 to k
forj=0 to k
if a[d[i]][d[j]]等于1并且e[i]等于e[j] then
flag=0;
break;
end if
if flag等于0 then break;
end for
if flag等于0 输出No
else 输出Yes
end if
end while
return 0
}
2.3.2代码截图
2.3.3本题PTA提交列表说明。
- Q1:一开始提交中只有最小图和最大图正确
- A1:在修改好多次后还是没能得到测试样例的正确答案,最后实在是写不动了,让舍友教我,然后才会写的
- Q2:舍友说这道题是广度遍历...我写的是深度遍历
- A2:主要是通过dfs的递归调用来实现遍历,本来我是写的是广度遍历的,因为自己画图的时候自己是有点像广度遍历那样,所以再写代码时候就以为用深度遍历,然后越搞越复杂,写了百来行代码,还搞不出来
3上机考试错题及处理办法
3.1.1截图错题代码:6-2 jmu-ds-图邻接表操作
3.2 错的原因及处理方法
深度遍历时候,指针指向下一个的时候,考试时候想错了,然后放在了如果没被遍历过的if语句中,导致超时,将语句放在if语句外就可以了
3.2.1截图错题代码:6-3 jmu-ds-拓扑排序
3.2 错的原因及处理方法
改正
可能是考试时候打得太快了...把大写G写成了小写g,while也写错了,写成了whlie...
3.1.1截图错题代码:7-1 六度空间
3.2 错的原因及处理方法
忘记用tail记录下每行的最后一个没被遍历的数,还有当时看题目搞错题目意思了,以为少于6是当等于7时候退出循环,主要是考试前特别慌这最后一场考试,经常去写去看这些pta代码,基本到最后都快能背下来了,连变量名都没换
3.1.1截图错题代码:7-2 公路村村通
3.2 错的原因及处理方法
忘记考虑了另外就是当数目不对时候也是不符合的情况,也要输出-1,还有就是之前不好理解的将最后一个没被遍历的那一行的首个置为0,在考试时候还是没注意到,又忘记了,最后还是没时间就没去细想了