[刷题之旅no25]P5318 【深基18.例3】查找文献

这么理解这道题:
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;
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值