1 条题解
-
0
「NordicOI 2024」Anime Shops 题解
题目理解
我们需要为每个城市找到到最近的其他动漫商店的距离。关键点:
- 如果城市本身有动漫商店,需要找另一个商店
- 距离指的是最短路径长度
- 如果无法到达任何其他商店,输出-1
关键观察
1. 问题转化
这是一个多源最短路径问题:
- 所有动漫商店都是起点
- 对于没有商店的城市,直接找最近的商店
- 对于有商店的城市,需要找次近的商店(排除自身)
2. 算法选择
多源BFS是最佳选择:
- 所有商店同时作为起点开始BFS
- 第一次访问某个节点时记录的距离就是最短距离
- 时间复杂度 ,适合大规模数据
算法思路
方法:多源BFS + 特殊处理
步骤1:初始化
#include <bits/stdc++.h> using namespace std; const int INF = 1e9; int main() { int n, m, k; cin >> n >> m >> k; vector<vector<int>> adj(n + 1); vector<int> dist(n + 1, INF); // 到最近商店的距离 vector<int> from_shop(n + 1, -1); // 最近的商店是哪个 vector<bool> is_shop(n + 1, false); queue<int> q;步骤2:读取输入并初始化BFS
// 读取动漫商店 for (int i = 0; i < k; i++) { int shop; cin >> shop; is_shop[shop] = true; dist[shop] = 0; from_shop[shop] = shop; q.push(shop); } // 读取道路 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; adj[a].push_back(b); adj[b].push_back(a); }步骤3:多源BFS
// 多源BFS while (!q.empty()) { int u = q.front(); q.pop(); for (int v : adj[u]) { if (dist[v] > dist[u] + 1) { dist[v] = dist[u] + 1; from_shop[v] = from_shop[u]; // 记录这个距离来自哪个商店 q.push(v); } } }步骤4:处理有商店的城市(需要找次近商店)
// 对于有商店的城市,需要找次近的商店 vector<int> second_dist(n + 1, INF); // 重新BFS,但跳过来自自身商店的路径 for (int i = 1; i <= n; i++) { if (is_shop[i]) { queue<pair<int, int>> q2; // (节点, 距离) vector<bool> visited(n + 1, false); // 从邻居开始,跳过自身 for (int neighbor : adj[i]) { if (from_shop[neighbor] != i) { // 不是来自自身商店的路径 second_dist[i] = min(second_dist[i], dist[neighbor] + 1); } else { // 如果邻居的最近商店是自身,需要BFS找次近 q2.push({neighbor, 1}); visited[neighbor] = true; } } // BFS找次近商店 while (!q2.empty()) { auto [u, d] = q2.front(); q2.pop(); if (from_shop[u] != i && is_shop[u]) { second_dist[i] = min(second_dist[i], d); continue; } for (int v : adj[u]) { if (!visited[v] && v != i) { visited[v] = true; q2.push({v, d + 1}); } } } } }步骤5:输出结果
// 输出结果 for (int i = 1; i <= n; i++) { if (is_shop[i]) { cout << (second_dist[i] == INF ? -1 : second_dist[i]) << " "; } else { cout << (dist[i] == INF ? -1 : dist[i]) << " "; } } return 0; }优化版本(更高效)
上面的方法对于有商店的城市进行了额外的BFS,可能较慢。下面是更优化的版本:
#include <bits/stdc++.h> using namespace std; const int INF = 1e9; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int n, m, k; cin >> n >> m >> k; vector<vector<int>> adj(n + 1); vector<int> dist(n + 1, INF); vector<int> from_shop(n + 1, -1); vector<bool> is_shop(n + 1, false); vector<int> second_dist(n + 1, INF); // 次近距离 // 读取商店 for (int i = 0; i < k; i++) { int shop; cin >> shop; is_shop[shop] = true; } // 读取道路 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; adj[a].push_back(b); adj[b].push_back(a); } // 第一次BFS:找到最近商店 queue<int> q; for (int i = 1; i <= n; i++) { if (is_shop[i]) { dist[i] = 0; from_shop[i] = i; q.push(i); } } while (!q.empty()) { int u = q.front(); q.pop(); for (int v : adj[u]) { if (dist[v] > dist[u] + 1) { dist[v] = dist[u] + 1; from_shop[v] = from_shop[u]; q.push(v); } } } // 第二次BFS:为有商店的城市找次近商店 // 使用多源BFS,但排除自身商店的影响 vector<int> temp_dist(n + 1, INF); queue<int> q2; for (int i = 1; i <= n; i++) { if (is_shop[i]) { // 从所有邻居开始,但排除来自自身商店的路径 for (int neighbor : adj[i]) { if (from_shop[neighbor] != i) { second_dist[i] = min(second_dist[i], dist[neighbor] + 1); } else { // 这些邻居的最近商店是i,需要继续探索 if (temp_dist[neighbor] > 1) { temp_dist[neighbor] = 1; q2.push(neighbor); } } } } } // BFS继续探索 while (!q2.empty()) { int u = q2.front(); q2.pop(); for (int v : adj[u]) { if (temp_dist[v] > temp_dist[u] + 1) { temp_dist[v] = temp_dist[u] + 1; // 如果找到其他商店,更新次近距离 if (is_shop[v] && from_shop[v] != from_shop[u]) { for (int shop = 1; shop <= n; shop++) { if (is_shop[shop] && from_shop[u] == shop) { second_dist[shop] = min(second_dist[shop], temp_dist[v]); } } } q2.push(v); } } } // 输出结果 for (int i = 1; i <= n; i++) { if (is_shop[i]) { cout << (second_dist[i] == INF ? -1 : second_dist[i]) << " "; } else { cout << (dist[i] == INF ? -1 : dist[i]) << " "; } } return 0; }算法正确性
关键点证明
- 多源BFS正确性:所有商店同时作为起点,确保找到全局最近商店
- 次近商店处理:通过排除自身商店的影响,找到真正的"另一个"商店
- 边界情况:正确处理孤立城市和无法到达的情况
复杂度分析
- 时间复杂度:
- 空间复杂度:
样例验证
样例输入分析:
9 6 4 2 4 5 7 1 2 1 3 1 8 2 4 3 4 5 6- 城市1:到商店2距离1
- 城市2:自身是商店,到商店4距离1
- 城市8:通过1到2,距离2
- 城市6:到商店5距离1
- 城市9:无连接,输出-1
总结
本题的关键在于:
- 使用多源BFS高效计算最近商店
- 特殊处理有商店城市的需求(找次近商店)
- 合理处理边界情况和无法到达的情况
这种"多源BFS + 特殊处理"的模式在解决最近设施类问题时非常有效。
- 1
信息
- ID
- 4437
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者