1.本周学习总结#

1.思维导图##

2.谈谈你对图结构的认识及学习体会。##

通过对图的学习,认识到了图的两种储存方法,还有图的深度遍历和广度遍历。相对树来说,本章学习的算法较多,如解决最小生成树问题的Prime、Kruskal算法,最短路径的Dijkstra、Floy算法。课后要及时巩固复习,不然真的很容易混淆起来。不仅要知道它们的原理,还要掌握算法的代码。其中,我个人觉得,Prime算法会比Kruskal算法复杂一点,Prime算法随着加入一个顶点,该顶点的最小边可能就需要修改。而Kruskal算法只要依此找最小边,确保它们不会出现回路。
图与树并不是毫不相关的两种结构,在上述算法中,图就转化成树来解决问题。树和图还是挺相似的,都是结点与结点间相互联系,但图的结构更复杂一些。图的结构适合去解决像公路村村通的问题,道路就像一张网,每条路都是相连在一起的。利用图的结构去解决这类问题再合适不过了。

2.PTA实验作业#

2.1题目1: 图着色问题##

2.1.1设计思路(伪代码)###

int main
定义color数组存放每个顶点的颜色
定义count数组
AdjGraph *G;  
定义n,e,p,num,k
输入n,e,p
调用CreateAdj函数
输入颜色个数num
for  j=0 to num
      k=0;
      color数组初始化为0
      for i=1 to G->n
      {
		cin>>color[i];
		count[color[i]]++;
	}
	统计count数组中值不为0的个数
	if(k!=p)
		 cout<<"No"<<endl;
        else
	{
		if(Judge(G,color)==1)
    	             cout<<"Yes"<<endl;
    	        else
    	             cout<<"No"<<endl;
	}	
void CreateAdj
创建一个结点p,存放邻接点,采用头插法插入结点p

int Judge
遍历每个顶点
       判断它的邻接点中是否有和它颜色相同的
       如果有就return 0
       没有就return 1

2.1.2代码截图###




2.1.3本题PTA提交列表说明。###

Q1:计算颜色种数的时候出错了,最大图的测试点出现段错误
A1:输入多组颜色数据后,count数组要初始化为0,一开始的代码为color[502]={0},但发现并没有将color数组初始化,就用循环将数组的每个元素置为0。段错误是因为没有注意到题目的要求,color数组和count数组长度定义的太小了。

2.2题目2:六度空间##

2.2.1设计思路(伪代码)###

定义全局变量
int n,m;
int count;
int a[10001][10001]={0};
int main
{
定义 i,b,c;
输入n,m
for  i=0 to m
	输入b,c
	a[b][c]=1;
	a[c][b]=1;
for  i=1 to n
	count=1;
	调用函数BFS(i);
	输出结点数占结点总数的百分比
}
void BFS(int x)
定义数组visited
定义队列q
定义i,j
定义level = 0 记录层数 
定义last = x 记录当前层数的最后一个元素 
定义tail 指向下一层最后一个元素
把x入队
visited[x]=1
while(!q.empty())
{
       取队头元素x
       x出队
       for i=1 to n
       {
             if  visited[i]==0&&a[x][i]==1
			count++;
			tail=i;
			visited[i]=1;
			i进队
       }
       if last==x
		level自增
		修改last的值为tail
	   如果level等于6结束循环
}

2.2.2代码截图###



2.2.3本题PTA提交列表说明。###

原本是用邻接表做,提交后只有21分,一直有问题。就网上找了这个代码,比原来的简洁。把顶点的邻接点进队,用last,tail,level分别记录当前层数的最后一个元素、下一层最后一个元素、层数,用这三个元素作为寻找与每个顶点每相距不超过6的结点,统计这些结点个数。只有当last等于队头元素时,level才自增,last才修改为tail,当level的值达到6,提前退出循环。

2.3题目3:公路村村通##

2.3.1设计思路(伪代码)###

定义全局变量
int s=0,n,e;
int g[4000][4000];
int lowcost[4000],closest[4000];
int main
{
      输入n,e
      调用函数CreateMGraph(n,e)
      if(Prim(1)==1)
	    输出s
      else
	    输出-1
}
void CreateMGraph(int n,int e )
定义i,j,a,b,c
数组所有元素初始化为9999
for i=1 to e
	输入a,b,c
	g[a][b]=c;
	g[b][a]=c;
	g[i][i]=0;
int Prim(int v)
定义min,i,j,k;
for  i=1 to n	
{   
	lowcost[i]=g[v][i];
	closest[i]=v;
}
for  i=1 to n	  
{
	min=9999;
    	for  j=1 to n
    	{
           如果 lowcost[j]的值不为0且小于min	
			 min=lowcost[j];  
			 k=j;
	    }
	 if  min==9999
		返回0 
	 s+=min;
	 标记k已经加入U lowcost[k]置为0
     for  j=1 to n	
	 如果g[k][j]的值不为0且小于lowcost[j]就对顶点进行调整
	    lowcost[j]=g[k][j];
		closest[j]=k;
}
返回1

2.3.2代码截图###



2.3.3本题PTA提交列表说明。###

Q1:部分正确
A1:数组g没有设初值,导致在判断输入数据不足以保证畅通的情况出现错误。该题采用Prime算法,参考了书上的代码。但一开始没有理解书上min=INF的意思,后来参考了同学代码,将min设为不存在边的g数组的值。通过循环,来判断各个顶点与其他顶点是否存在边,既min的值有没有被改变,从而输出-1。

3、上机考试错题及处理办法#

3.1截图错题代码##



3.2 错的原因及处理方法##

这题按自己的做法只能部分正确,于是网上找了代码,网上的代码更简洁,但没有真正理解代码,把if(last==x)、if(level==6)的这两段代码放到for循环中,发现输出结果错误后,又把那两段代码放到if(visited[i]==0&&a[w][i]==1)里面,结果还是错误的。应该是先把所有顶点都入队后,再开始后面的操作。所以if(last==x)、if(level==6)的这两段代码要放在for循环外面,问题就解决了。