当我学习图的存储与dfs bfs的遍历时……

本文介绍了如何解决洛谷5518题,探讨了图的存储方法,包括邻接矩阵和邻接表,并通过C++实现了深度优先搜索(DFS)和广度优先搜索(BFS)。作者分享了从二维数组到结构体存储的转变过程,以及在实际编码中遇到的问题和解决方案,展示了在大规模数据下优化图遍历算法的重要性。
摘要由CSDN通过智能技术生成
  • 题目是洛谷5518

  • 拿到题目我就知道我不会做,于是赶紧看看题解。

  • 首先是图的存储,一般来说,图的存储使用两种方法:

    • 邻接表:有点复杂,我就没看
      在这里插入图片描述
    • 邻接矩阵:非常简单好理解,就是个二维数组
      在这里插入图片描述
  • 二是dfs 递归思想,相对简单

  • 三是bfs 这一步要用到 队列

    • 虽然数据结构早就学过了,没办法辣鸡的我不会,又去学队列
      大佬关于队列的博客
      于是我写出了第一版代码
#include<iostream>
using namespace std;
const int N=1e5+10;
int wx[1001][1001],flag1[1001]={0},flag2[1001]={0},q[1001]={0};
int n,m;
void clear(int n) {
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			wx[i][j]=0;
}
void dfs(int node)
{
	cout<<node<<" ";
	flag1[node]=1;
	for(int i=1;i<=n;i++)
	{
		if(wx[node][i]==1&&flag1[i]==0)
			dfs(i);
	}
	return ;
}
void bfs(int node)
{
	int head=0,tail=1;
	q[head]=node;
	flag2[node]=1;
	cout<<node<<" ";
	while(tail>head)
	{
	for(int i=1;i<=n;i++)
	{
		if(wx[node][i]==1&&flag2[i]==0)
		{
			q[tail]=i;
			tail++;
			flag2[i]=1;
			cout<<i<<" ";
		}	
	}
	node=q[head++];
	}
}
int main()
{
	cin>>n>>m;
	clear(n);
	for(int i=0;i<m;i++)
	{
		int a,b;
		cin>>a>>b;
		wx[a][b]=1;
	}
	dfs(1);
	cout<<endl;
	bfs(1);
	return 0;
 } 
  • 此时我已经过了样例,不过我早就知道,我的数据范围太小,不可能AC。本题数据范围是1e5,明显二维数组不可行。为什么我会知道呢(因为我看题解了啊
  • 那没办法我还要继续看题解 学习。
  • 既然邻接矩阵不行,就只能用邻接表喽
  • 所以开始学习邻接表,看到题解中的大佬们写的用 or 等看不懂的东西,我果断百度了一下,好神奇呢我还是看不懂呢 ,于是我果断放弃,转而去看实验室讲图论的大佬的ppt
    在这里插入图片描述
  • 看起来挺简单的不过不还是二维数组存N吗?数组应该还是会爆吧,但是本着学习的念头我还是要写出来试试。(因为这个也不会
    于是写出的第二版代码如下
#include<iostream>
using namespace std;
const int N=1e5+10;
int wx[1001][1001],flag1[1001]={0},flag2[1001]={0},q[1001]={0};
int n,m;
//struct wenxian{
//	int last;
//	int next;
//	//int node;
//}wx[N];
void clear(int n) {
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			wx[i][j]=0;
}
void dfs(int node)
{
	cout<<node<<" ";
	flag1[node]=1;
	for(int i=1;i<=wx[node][0];i++)
	{
		if(flag1[wx[node][i]]==0)
			dfs(wx[node][i]);
	}
	return ;
}
void bfs(int node)
{
	cout<<node<<" ";
	int head=0,tail=1;
	q[head]=node;
	flag2[node]=1;
	while(head<tail)
	{
		for(int i=1;i<=wx[node][0];i++)
		{
			if(flag2[wx[node][i]]==0)
			{
				flag2[wx[node][i]]=1;
				q[tail]=wx[node][i];
				tail++;
				cout<<wx[node][i]<<" ";
			}
		}
		node=q[head++];
	}
}
int main()
{
	cin>>n>>m;
	clear(n);
	for(int i=0;i<m;i++)
	{
		int a,b;
		cin>>a>>b;
		wx[a][0]++;
		wx[a][wx[a][0]]=b;
	}
	dfs(1);
	cout<<endl;
	bfs(1);
	return 0;
 } 
  • 但我在写的过程中发现一个严重的问题,题目要求遍历过程从小到大排序,但似乎sort函数无法实现二维数组的排序?其他排序肯定巨麻烦,而且我也知道这个二位数组在N下会爆,所以开始看大佬写的ppt的下一个方法。
  • 方法二是一个结构体,我觉得这个方法存应该就对了,毕竟看起来就和题解中的好像
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021042120042在这里插入图片描述
    在这里插入图片描述
  • 看了一会感觉这个方法似乎和之前看过的xx向前*有异曲同工之妙,head[]记录的是每个开始点到最后结束点的边的序号。
  • 最后我写出了它的储存图的代码,但是问题是这种方法是倒着存的,对于有向图无论是bfs还是dfs都不知道咋写,我也没查到相关的,况且题目要求排序,这我就更不会了。那只能先放弃这个了,我果断决定下一步要直接看题解。
  • (大无语事件) 找到一个和刚才方法相似的题解,理解了两个小时写出了一个代码,然后发现自己刚才学的那个结构体其实是完全可以dfs的,只不过我的dfs写错了……而且其实那个方法比题解还简单……
  • 但是写都写了不能浪费,我先写完看看吧。结果哭死孩子,只会写dfs,bfs写不出来……
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int head[N]={0},next[N]={0},flag1[1001]={0},flag2[1001]={0},q[1001]={0},num=0;
int n,m;
struct www{
	int from,toto;
}ww[N];
bool cmp(www a,www b){
	if(a.from!=b.from)
		return a.from>b.from;
	return a.toto>b.toto;
}
void clear() {
	for(int i=0;i<N;i++)
	{
		ww[i].from=0;
		ww[i].toto=0;
		head[i]=0;
	}
}
void add_wx(int a,int b)
{
	next[++num]=head[a];
	head[a]=num;
}
void dfs(int node)
{
	cout<<node<<" ";
	flag1[node]=1;
	while(head[node])
	{
		if(flag1[ww[head[node]].toto]==0)
		{
			dfs(ww[head[node]].toto);
		}
		head[node]=next[head[node]];
	}
	return ;
}
int main()
{
	cin>>n>>m;
	clear();
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>ww[i].from>>ww[i].toto;
	}
	sort(ww+1,ww+m+1,cmp);
	for(int i=1;i<=m;i++)
		add_wx(ww[i].from,ww[i].toto);
	dfs(1);
	cout<<endl;
//	bfs(1);
	return 0;
 } 
  • 我知道为啥bfs出不来了,代码没有啥大错,但是head数组在dfs时被全部清空了……小垃圾不会别的,于是只好把head复制一个为hhead,让他来bfs。
  • 最后的最后,还是过了,不说了上代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int head[N]={0},hhead[N]={0},next[N]={0},flag1[N]={0},flag2[N]={0},q[N]={0},num=0;
int n,m;
struct www{
	int from,toto;
}ww[N];
bool cmp(www a,www b){
	if(a.from!=b.from)
		return a.from>b.from;
	return a.toto>b.toto;
}
void clear() {
	for(int i=0;i<N;i++)
	{
		ww[i].from=0;
		ww[i].toto=0;
		head[i]=0;
	}
}
void add_wx(int a,int b)
{
	next[++num]=head[a];
	head[a]=num;
}
void dfs(int node)
{
	cout<<node<<" ";
	flag1[node]=1;
	while(head[node])
	{
		if(flag1[ww[head[node]].toto]==0)
		{
			dfs(ww[head[node]].toto);
		}
		head[node]=next[head[node]];
	}
	return ;
}
void bfs(int node)
{
	cout<<node<<" ";
	int head1=0,tail=1;
	q[head1]=node;
	flag2[node]=1;
	while(head1<tail)
	{
		for(int i=hhead[node];i;i=next[i])
	//	while(hhead[node]!=0||)
		{
			//int i=hhead[node];
			if(flag2[ww[i].toto]==0)
			{
				flag2[ww[i].toto]=1;
				q[tail]=ww[i].toto;
				tail++;
				cout<<ww[i].toto<<" ";
				hhead[node]=next[hhead[node]];
			}
		}
		node=q[head1++];
	}
}
int main()
{
	cin>>n>>m;
	clear();
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>ww[i].from>>ww[i].toto;
	}
	sort(ww+1,ww+m+1,cmp);
	for(int i=1;i<=m;i++)
		add_wx(ww[i].from,ww[i].toto);
	for(int j=0;j<=N;j++)
		hhead[j]=head[j];
	dfs(1);
	cout<<endl;
	bfs(1);
	return 0;
 } 
  • 有一点我还不是太清楚,就是
  • for(int i=hhead[node];i;i=next[i])
  • 题解里大佬这么写的,我也是头一次看到……因为我写的循环条件有问题,但我不知道哪有问题……而且也不会改……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值