链式前向星 学习笔记

板子题-图的dfs

题目描述

一个有n个节点的连通图,这些节点以编号:\(1,2,……n\) (\(1\leq n,e\leq 1000000\))进行编号,现给出节点间的连接关系。请以节点1为起点,按dfs的顺序遍历并输出该图。

输入

第一行为两整数,\(n\)\(e\),表示\(n\)个顶点,\(e\)条边
以下\(e\)行每行两个数,表示两个节点是联通的

输出

只有一行,为节点的dfs顺序

样例输入

5 6
1 2
1 3
1 4
2 4
3 5
4 5

样例输出

1 2 4 5 3

算法理解

这道题目,其实可以使用简单的邻接矩阵,但是,对于一个稀疏图来说,这会很浪费空间。就比如说这样的一张图:

graph LR A((1))-->B((2)) A((1))-->B1((3)) A((1))-->B2((...)) A((1))-->B3((1000))

如果使用邻接矩阵来储存的话,会非常浪费空间的,如果\(n\)的值很大的话保证MLE甚至RE那么,我们该怎么办呢?

算法实现

链式前向星就可以解决。这是利用链表进行操作的,没有学过链表的同学可以点这里

邻接表的构造

上图(样例):

graph LR 1((1))-->2((2)) 1-->3((3)) 1-->4((4)) 2-->4 3-->5((5)) 4-->5

用邻接表来表示就是这样的:

起始点 到达点1 到达点2 到达点3
1 2 3 4
2 4 / /
3 5 / /
4 5 / /
5 / / /
我们把这5条链表都存放在一个数组当中。用一个\(head\)数组,其中\(head_i\)表示第\(i\)个点头指针。然后就是数据域\(to\)和指针域\(nex\)就可以了,当\(nex_i\)的值为\(-1\)的时候,就证明这个点是链表的结尾。

插入

还是来一张图(下标从\(1\)开始):
在这里插入图片描述
很简单,先把这个点的后驱设置为头,然后把头设置为这个点即可。
代码实现:

void add(int x,int y){
	to[k]=y;
	nex[k]=head[x];
	head[x]=k;
	k++;
	return;
}

使用

插入之后,那么怎么用呢?是个问题。
不说了,看代码:

void dfs(int cur){
	if(see[cur]) return;//如果去过就fanhui
	printf("%d ",cur);//输出路径
	see[cur]=1;//标记
	for(int i=head[cur];i!=-1;i=nex[i]){//像链表一样查找
		dfs(to[i]);//继续递归
	}
	return;
} 

广告:如果你没有学过DFS,可以看这里

题目解析

其实,如果把这两段代码以及主函数写好,是过不了样例的,因为最重要的是按照字典序排列,所以,还要加上一段sort,当然因为地址不连续,就要自己打了,发现自己sort用太多连冒泡都不会打了
一切都在代码里::

void my_sort(int x){//x代表从x开始的点的排序
	int f,a[maxn],nn;//f储存当前节点
	f=head[x];//a储存地址
	nn=0;//nn储存这个点的出度
	memset(a,0,sizeof(a));//清零
	while(f!=-1){//记录每一个数的地址
		nn++;//统计数量
		a[nn]=f;
		f=nex[f]
	}
	if(nn==1||nn==0) return;//如果只有一个或者没有直接返回
	int tmp,flag=1;
	for(register int i=1;i<=nn;i++){//冒泡排序
		flag=1;
		for(register int j=nn-1;j>=i;j--)
		    if(to[a[j]]>=to[a[j+1]]){
		    	flag=0;
		    	tmp=to[a[j]];
				to[a[j]]=to[a[j+1]];
				to[a[j+1]]=tmp;
		    }
		if(flag) return;//小优化
	}
	return;   
}

然后是你们~最~\(最\)爱的AC代码::

#include<cstdio>
#include<cstring>
#define maxn 100039
using namespace std;
int to[maxn],nex[maxn],head[maxn],k;
int n,m,i,x,y;
void add(int x,int y){
	to[k]=y;
	nex[k]=head[x];
	head[x]=k;
	k++;
	return;
}
void my_sort(int x){
	int f,a[maxn],nn;
	
	f=head[x];
	nn=0;
	
	memset(a,0,sizeof(a));
	while(f!=-1){
		nn++;
		a[nn]=f;
		f=nex[f];
	}
	if(nn==1||nn==0) return;
	int tmp,flag=1;
	for(register int i=1;i<=nn;i++){
		flag=1;
		for(register int j=nn-1;j>=i;j--)
		    if(to[a[j]]>=to[a[j+1]]){
		    	flag=0;
		    	tmp=to[a[j]];
				to[a[j]]=to[a[j+1]];
				to[a[j+1]]=tmp;
		    }
		if(flag) return;
	}
	return;   
}
int see[maxn];
void dfs(int cur){
	if(see[cur]) return;
	printf("%d ",cur);
	see[cur]=1;
	for(int i=head[cur];i!=-1;i=nex[i]){
		dfs(to[i]);
	}
	return;
} 
int main(){
	memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){
    	scanf("%d%d",&x,&y);
    	add(x,y);
    }
    for(i=1;i<=n;i++)
        my_sort(i);
    dfs(1);
	return 0;
}

注:这是我的成果(62行的代码),请勿抄袭!
广告:我的博客 欢迎各位大佬们前来指教本蒟蒻

posted @ 2021-02-15 21:14  jiangtaizhe001  阅读(105)  评论(0)    收藏  举报