这么理解这道题:
1.用合适的数据结构储存图
2.分别用dfs和bfs对图进行遍历
一共有10的五次方个结点,所以如果用二维数据储存路径显然不可行
剩下的数据结构还有各种各样的表
我需要什么呢?我需要给出一个结点,可以找到其能够直接到达的所有结点
这样的话,链式前向星可以用来存图(好万能)存图过程中还需要判断结点大小进行插入。
然后对当前结点进行遍历,深搜即可。由于论文不可以相互引用,所以所有结点都是单向的
深搜:
给一个结点,遍历和当前结点直接相连的所有结点,遍历一个,打印一个,递归一个
广搜:
给一个结点,遍历和当前结点相连的所有结点,全都打印出来,然后全都递归。
数据结构,链式前向星,而且需要从小到大排序
所以需要有人不断向后遍历,直到找到属于你的位置即可。
所以需要edge.next;
失败
出现了一些问题
creat函数出现了极其严重的逻辑错误!!好蠢啊你
但是我还是找不出任何问题,确实是没有错误
那么就是dfs和bfs中间出现了逻辑错误
dfs中出现的逻辑错误,打印结点应该在循环之外,我们只需要利用循环进行递归
bfs出现的错误(我还不是很熟悉bfs,待会儿需要学习一下)
我的bfs逻辑会导致最高层和最底层打印不出来
(对了,可以弄一个node数组,进行记录,如果打过了,就不打了)
空间复杂度超出了限制,说明,我的递归出现了不可终止现象,也就是我的这个递归在面对环形结构的时候出现了死循环
我需要想办法终止递归、
好吧,这道题具有相当大的价值
1.图的储存形式
2.图的深搜广搜,并且如何避免出现死循环都是问题
没时间了,呜呜,直接看答案学习一下吧
储存形式和我差不多,链式前向星还是好用的
深度优先搜索:
防止绕晕:无限递归
也就是判断终点应该在该不该递归而不是该不该打印的问题上面
所以直接对传入结点进行标记,打印结点
然后找到和结点相邻的所有边对应的结点
如果结点没走过再递归,这一步是解决无限递归问题的精髓所在。
广度优先搜索:
需要用到队列的思想
先把第一个结点推入到队列之中
然后对该点进行标记,输出
!广度优先搜索考得是循环而不是递归!
然后只要队列不是空的
我就:
取出当前队首元素
遍历查找于之相连的所有结点
遇到一个看看有没有标记
没有标记的
标记-打印-入队
这样循环往复,直到结束。
代码:
#include<stdio.h>
typedef struct
{
int to,next;//to是当前边到达的结点编号,next是和当前结点相连的下一条边的而编号
}Edge;
Edge edge[1000005];
int head[100005]={0},nodef[100005][2]={0},line[100005]={0};//head数组,下标就是结点编号,数组值就是和当前编号的结点相连的第一条边的编号
int numNode=0,numEdge=0,from=0,end=0,cnt=0,heade=1,tail=1;
void bfs(int node);
void dfs(int node);
void createdge(int from,int end);
int main()
{
scanf("%d %d",&numNode,&numEdge);
for(int i=1;i<=numEdge;i++)
{
scanf("%d %d",&from,&end);
createdge(from,end);
}
dfs(1);
printf("\n");
bfs(1);
printf("\n");
return 0;
}
void bfs(int node)
{
line[tail]=node;
printf("%d ",node);
nodef[node][1]=1;
int pos;
while(heade<=tail)
{
pos=line[heade];
for(int i=head[pos];i;i=edge[i].next)
{
//遇到的,如果没有打印过,直接三件套服务
if(nodef[edge[i].to][1]==0)
{
nodef[edge[i].to][1]=1;
printf("%d ",edge[i].to);
tail++;
line[tail]=edge[i].to;
}
}
heade++;
}
return ;
}
void dfs(int node)
{
nodef[node][0]=1;
printf("%d ",node);
for(int i=head[node];i;i=edge[i].next)
{
if(nodef[edge[i].to][0]==0)//说明没走过
{
dfs(edge[i].to);
}
}
return ;
}
void createdge(int from,int end)
{
cnt++;
int i=head[from];
if(i==0||end<edge[i].to)//空的
{
edge[cnt].next=head[from];
edge[cnt].to=end;
head[from]=cnt;
return ;
}
else
{
while(1)//当前到达的地方的编号和当前和from直接相连的结点进行比较
{
//中间或者最后
if(edge[i].next==0||end>edge[i].to&&end<edge[edge[i].next].to)//比你大,你就向后走
{
edge[cnt].to=end;
edge[cnt].next=edge[i].next;
edge[i].next=cnt;
return ;
}
else
{
i=edge[i].next;
}
}
}
}