链式前向星 学习笔记
板子题-图的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行的代码),请勿抄袭!
广告:我的博客 欢迎各位大佬们前来指教本蒟蒻