# U410472 【模板】dfs序

U410472 【模板】dfs序

题目背景

关于 dfs 序是访问一棵树时将其按照 dfs 时访问的先后顺序打上序号。于是,通过 O(n) 的扫一遍树上的每个点就可以把非线性的树形结构转成线性的区间结构。

题目描述

给定一颗树,输出这棵树的dfs序,并且输出dfs的入时间戳和出时间戳。根节点默认为1的无向图。

输入格式

输入节点的个数 n (n<=10^5)

接下来输入 n-1 行,每次输入两个节点代表一条边。

边集数组来构成这颗树。

输出格式

输出这颗树的dfs序,同一层的节点,优先考虑数字小的节点。
然后换行输出dfs序的入时间戳序列。
换行输出dfs序的出时间戳序列。

输入输出样例 #1

输入 #1

9
1 2
1 3
2 4
2 5
3 6
5 7
5 8
7 9

输出 #1

124579836
128349576
979379676

第一步 定义

点击查看代码
dge* head[MAXN]; //节点的邻接表头指针数组
int visited[MAXN];
int dfs_order[MAXN]; // DFS访问顺序
int in[MAXN], out[MAXN]; //入时间戳 和 出时间戳
int time = 1, now = 0;
• 入时间戳 in[u]:第一次“进入”节点 u 时的时刻(DFS 开始处理这个节点) • 出时间戳 out[u]:在递归完成 u 所有子节点的处理后,“离开”节点 u 的时刻(DFS 即将回退到父节点) **第二步 建图:将边(u, v)插入head[u],保持升序**
点击查看代码
// 建图:将边(u, v)插入head[u],保持升序
void add_edge(int u, int v) {
    Edge* new_edge = (Edge*)malloc(sizeof(Edge));
    new_edge->to = v;
    new_edge->next = NULL;

    // 插入有序位置
    if (head[u] == NULL || head[u]->to >= v) {
         //如果满足就把 new_edge 插入到链表最前面
        new_edge->next = head[u];
        head[u] = new_edge;
        return;
    }

    Edge* prev = head[u];
    Edge* curr = head[u]->next;

    while (curr && curr->to < v) {
        prev = curr;
        curr = curr->next;
    }

while (curr && curr->to < v) { prev = curr; curr = curr->next; }的意思是
• 当 curr 还没到链表尾部,并且当前节点的编号小于要插入的 v,就继续往后走。
• 更新 prev = curr,让 prev 指向当前节点;
• 然后 curr = curr->next,继续往后看。

完整代码
点击查看代码
#include <stdio.h>
#include <stdlib.h>

#define MAXN 100002

typedef struct Edge {
    int to;
    struct Edge* next;
} Edge;

Edge* head[MAXN]; //节点的邻接表头指针数组
int visited[MAXN];
int dfs_order[MAXN];    // DFS访问顺序
int in[MAXN], out[MAXN];
int time = 1, now = 0;

void add_edge(int u, int v){
    Edge* new_edge = (Edge*)malloc(sizeof(Edge));
    new_edge->to = v;
    new_edge->next = NULL;

    // 插入有序位置
    if (head[u] == NULL || head[u]->to >= v) {
        new_edge->next = head[u];
        head[u] = new_edge;
        return;
    }

    Edge* prev = head[u];
    Edge* curr = head[u]->next;

    while (curr && curr->to < v) {
        prev = curr;
        curr = curr->next;
    }

    new_edge->next = curr;
    prev->next = new_edge;
}
void dfs(int u){
    visited[u] = 1;
    in[u] = time++;                 // 记录进入时间戳
    dfs_order[now++] = u;          // 加入DFS序

    for (Edge* e = head[u]; e != NULL; e = e->next) {
        if (!visited[e->to]) {
            dfs(e->to);
        }
    }

    out[u] = time++;
}
int main() {
    int n;
    scanf("%d", &n);

    // 读取n-1条边(树)
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        scanf("%d %d", &u, &v);
        add_edge(u, v);
        add_edge(v, u); // 因为是无向图
    }

    dfs(1); // 从根节点1开始DFS

    // 输出 DFS 序
    for (int i = 0; i < now; ++i)
        printf("%d", dfs_order[i]);
    printf("\n");

    // 输出 入时间戳
    for (int i = 1; i <= n; ++i)
        printf("%d", in[i]);
    printf("\n");

    // 输出 出时间戳
    for (int i = 1; i <= n; ++i)
        printf("%d", out[i]);
    printf("\n");

    return 0;
}
posted @ 2025-05-25 00:33  sirro1uta  阅读(21)  评论(0)    收藏  举报