Skip to main content
A cup of beer
  1. Posts/

SDUOJ 网络铺设题解 (BFS链式前向星)

·344 words·2 mins

问题描述 #

你现在是城市的主人 现在有 nn 个村庄,已经修建了 n-1n−1 条道路,使得各个村庄作为节点,路作为边,构成一棵树。 假设第 aa 个村庄到第 bb 个村庄有路相连,则从 aa 走到 bb 或者从 bb 走到 aa 需要走 1\text{m}1m 。

你需要输出 nn 个数,第 ii 个数代表从第 ii 个村庄出发,距离他最远的村庄的距离

输入格式 #

第一行一个整数 nn , 0\le n\le10^50≤n≤105 接下来有 n-1n−1 行,每行 a,ba,b 代表第 aa 个村庄,到第 bb 个村庄有一条路。 1\le a,b\le 10^51≤a,b≤105

保证输入结构是一棵树

输出格式 #

输出一行 nn 个数,表示答案

样例输入 #

5
5 1
1 2
2 3
3 4

样例输出 #

3 2 3 4 4

数据结构 #

node结构体 #

标识符 解释
next 链表节点的next域
num 节点编号

链式前向星的数据 #

标识符 解释
sn 最近新建的node在申请空间中的下标
storage[0…300002] 存储所有的链表节点
nodes[0…105001] 存储所有的头节点

算法数据 #

标识符 解释
max1[0..105001] 从第一个最大的点到各个点的距离
max2[0..105001] 从第二个最大的点到各个点的距离

算法设计 #

构建链式前向星 #

先在nodes数组中初始化n个域,表示n个图节点。

为他们分别安排哨兵:让所有的头节点的next都为num=-1,next=-1.(以后如果要往这个链上插入新点,都是要在头节点和头节点的next之间插入,这样复杂度最低。我们哨兵的作用是无需单独处理这条链为空的情况。

写好构建单向边的函数:让sn++,代表申请内存空间,然后按链表的方式操作即可。注意遵循链式前向星的插入方法:即头节点和其next之间。

写好构建双向边的函数:两次调用上述函数。

四次BFS解决问题 #

这里BFS需要额外加一个操作:每次BFS新节点入队时,记录新节点的距离是当前节点的+1.

关键问题 #

无。

代码实现 #

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MOD = 1000000007;

struct Node
{
    int next;
    int num;
    Node() :next(-1), num(-1) {};
};

int n, iv1, iv2, sn;
int max1[105001], max2[105001];
Node storage[300002];
Node nodes[105001];

void createEdge(int v1, int v2) {
    int newNode = ++sn;
    storage[newNode].num = v2;
    storage[newNode].next = nodes[v1].next;
    nodes[v1].next = newNode;
}

void addNewEdge(int v1, int v2) {
    createEdge(v1, v2);
    createEdge(v2, v1);
}

int bfs(int start,bool mode,bool key) {
    int cur = nodes[start].next;
    int last = start;
    queue<int> q;
    set<int> vis;
    while (storage[cur].next!=-1)
    {
        q.push(storage[cur].num);
        cur = storage[cur].next;
    }
    while (!q.empty())
    {
        int theNum = q.front();
        q.pop();
        vis.insert(theNum);
        last = theNum;
        cur = nodes[theNum].next;
        while (storage[cur].next != -1)
        {
            if (!vis.count(storage[cur].num)) {
                q.push(storage[cur].num); 
                if (mode)key ? max1[storage[cur].num] = max1[theNum] + 1 : max2[storage[cur].num] = max2[theNum] + 1;
            }
            cur = storage[cur].next;
        }
    }
    return last;
}

void solve() {
    int far1 = bfs(1,false,false);
    int far2 = bfs(far1,false,false);
    bfs(far1, true, true);
    bfs(far2, true, false);
    for (int i = 1; i <= n; i++)printf("%d ", max(max1[i]+1, max2[i]+1));
    puts("\n");
}

int main() {
    //freopen("C:\\Users\\Lenovo\\Desktop\\a.in", "r", stdin);
    //freopen("C:\\Users\\Lenovo\\Desktop\\a.out", "w", stdout);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int newNode = ++sn;
        nodes[i].num = i; 
        nodes[i].next = newNode;//哨兵
    }
    for (int i = 1; i <= n - 1; i++) {
        scanf("%d %d", &iv1, &iv2);
        addNewEdge(iv1, iv2);
    }
    solve();
}