Works Applications2016校园招聘 — Travel Information Center

本文详细阐述了解决Aps岛节日城市与旅行者距离问题的两种算法解决方案,包括一种用于更新城市状态以减少信息中心负担的方法,以及另一种在查询时直接寻找最近节日城市的广度优先搜索方法。同时,提供了代码实现和输入输出示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem


Aps Island has many cities. In the summer, many travellers will come to the island and attend festive events in different cities. The festive events in Aps Island are crazy. Once it starts, it will never end. In the following sentences, the cities which have festive events are called festive cities.

At the beginning, only city No. 1 is festive city. If a new city becomes festive city, the government will tell the information center about this news.

Everyday, the information center will receive many inquiries from travellers from different cities of this land. They want to know the closest festive city, and calculate the distance (If current city has festive event, the distance is 0).

Due to the growing number of the travellers, the information center is overloaded. The government wants to fix the problem by developing a system to handle the inquiries automatically.

As a fact, cities in Aps Island are connected with highways(bidirectional, length of every highway is 1). Any two cities are connected directly or indirectly, and there is ONLY one path between any 2 cities.

Input

There are two integers in the first line, n (2 ≤ n ≤ 10^5) and m ( 1 ≤ m ≤ 10^5), n is the number of cities in the Aps Island and m is the number of queries. The coming n-1 lines are the highways which connect two cities. In the line, there are two integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi), representing two cities. Each line means the highway connecting the two cities.

Next m lines are inquiries from travellers or news from government. Each line has two integers qi and ci (1 ≤ qi ≤ 2, 1 ≤ ci ≤ n). If qi = 1, the government announces a new festive city ci. If qi = 2, you have to find and print the shortest distance from the city ci to the closest festive city.

Output

Results from each (qi = 2) Questions. Print every result with a new line.

Sample Test


input

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

output

2
1
0
1

Solution 1


思路

用dis[i]表示节点i离最近标记节点的距离,每次标记新的节点时递归更新所有节点状态,有剪枝。最后在查询的时候直接输出dis[x]即可。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;

struct Node {
    vector<int> eds;
};
Node node[100001];
int dis[100001];    //dis[i]表示结点i离最近标记结点的距离
int m, n;

//更新以x为根节点,p为x的父节点的子树的状态,有剪枝
void dfs(int x, int p) {
    vector<int> vecs = node[x].eds;
    for (int i = 0; i < vecs.size(); ++i) {
        if (vecs[i] == p)
            continue;
        if (dis[vecs[i]] == -1 || dis[vecs[i]] > dis[x] + 1) {
            dis[vecs[i]] = dis[x] + 1;
            dfs(vecs[i], x);
        }
    }
}

int main() {
    memset(dis, -1, sizeof(dis));

    scanf("%d%d", &m, &n);
    int a, b;
    for (int i = 1; i < m; ++i) {
        scanf("%d%d", &a, &b);
        node[a].eds.push_back(b);
        node[b].eds.push_back(a);
    }
    dis[1] = 0;
    dfs(1, 0);
    for (int i = 0; i < n; ++i) {
        scanf("%d%d", &a, &b);
        if (a == 1) {
            dis[b] = 0;
            dfs(b, 0);
        }
        else {
            printf("%d\n", dis[b]);
        }
    }
    return 0;
}

Solution 2


思路

solution 1中,如果当所有节点连成一条“直线”的时候,更新节点状态的时候不知道会不会爆栈。现在还有另外一种方法就是,我们在标记新的节点时只是单纯记录下标记节点即可,在每次查询的时候再利用广搜找到最近标记节点。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;

struct Node {
    bool flag;    //记录该节点是否被标记
    vector<int> eds;

    Node() {
        flag = false;
    }
};
Node node[100001];
int m, n;

struct State {
    int par;    //父节点
    int no;
    int dis;
};

int bfs(int x) {
    queue<State> que;
    State sta;
    sta.par = 0;
    sta.no = x;
    sta.dis = 0;
    que.push(sta);
    while (!que.empty()) {
        State cur = que.front();
        que.pop();
        if (node[cur.no].flag)
            return cur.dis;
        vector<int> vecs = node[cur.no].eds;
        for (int i = 0; i < vecs.size(); ++i) {
            if (vecs[i] == cur.par)
                continue;
            State ns;
            ns.par = cur.no;
            ns.no = vecs[i];
            ns.dis = cur.dis + 1;
            que.push(ns);
        }
    }
}

int main() {
    scanf("%d%d", &m, &n);
    int a, b;
    for (int i = 1; i < m; ++i) {
        scanf("%d%d", &a, &b);
        node[a].eds.push_back(b);
        node[b].eds.push_back(a);
    }

    node[1].flag = true;
    for (int i = 0; i < n; ++i) {
        scanf("%d%d", &a, &b);
        if (a == 1) {
            node[b].flag = true;
        }
        else {
            int dis = bfs(b);
            printf("%d\n", dis);
        }
    }
    return 0;
}

目前能想到的只有这两种方法了,虽然都能AC,但总感觉还有更优化的方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值