H - Find a way(两次bfs)

本文介绍了一个关于寻找两个人到达同一地点最短总时间的问题,并通过使用广度优先搜索(BFS)算法解决这一问题。文章提供了完整的C++代码实现,展示了如何在一张地图上找到从两个不同起点到特定目标点的最短路径。

H - Find a way

Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.
Input
The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200).
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’ express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF
Output
For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.
Sample Input

4 4
Y.#@
....
.#..
@..M
4 4
Y.#@
....
.#..
@#.M
5 5
Y..@.
.#...
.#...
@..M.
#...#

Sample Output
66
88
66

题意:
Y和M到达同一个’@’点的最短距离(注意算完步数之后,要*11)
bfs 两次,要注意在第二次开始的时候,要将标记数组清零~

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MAXN 267
char ma[MAXN][MAXN];//存图
int n, m;//图的大小
int v[MAXN][MAXN];//标记数组
struct node
{
    int x, y, step;//x坐标,y坐标,及到达此点的步数
}t, p, q, que[121212];
int ans[MAXN][MAXN];//记录到达@点的步数
int vectors[][2] = {1, 0, -1, 0, 0, 1, 0, -1};//上下左右四个方向
void bfs(int x, int y)
{
    v[x][y] = 1;//标记
    int front = 0, rear = 0;
    p.x = x;
    p.y = y;
    p.step = 0;
    que[rear++] = p;//入队
    while(front<rear)
    {
        q = que[front++];
        for(int i=0;i<4;i++)//四个方向遍历
         {
            p.x = q.x + vectors[i][0];
            p.y = q.y + vectors[i][1];
            if(p.x<0||p.x>=n||p.y<0||p.y>=m||v[p.x][p.y]||ma[p.x][p.y]=='#')
                 continue;//不符条件
            if(ma[p.x][p.y]=='@')//如果是终点
            {
                ans[p.x][p.y] += q.step + 1;//记录步数
            }
            v[p.x][p.y] = 1;//标记
            p.step = q.step+1;//更新步数
            que[rear++] = p;//入队
            }
    }
    return ;
}
int main()
{

    while(~scanf("%d %d", &n, &m))
    {
    memset(ans, 0, sizeof(ans));//清零
    for(int i=0;i<n;i++)
        scanf("%s", ma[i]);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(ma[i][j]=='Y')
            {
                t.x = i;//记录横坐标
                t.y = j;//记录竖坐标
                t.step = 0;
            }
        }
    }
    memset(v, 0, sizeof(v));
    bfs(t.x, t.y);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(ma[i][j]=='M')
            {
                t.x = i;
                t.y = j;
                t.step = 0;
            }
        }
    }
    memset(v, 0, sizeof(v));//记得清零
    bfs(t.x, t.y);
    int min = 989898;//定义一个大一点的数
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
              if(ans[i][j]<min&&ans[i][j])
                    min = ans[i][j];
        }
    }
    printf("%d\n", min*11);//别忘了*11
    }
    return 0;
}
物联网通信协议测试是保障各类设备间实现可靠数据交互的核心环节。在众多适用于物联网的通信协议中,MQTT(消息队列遥测传输)以其设计简洁与低能耗的优势,获得了广泛应用。为确保MQTT客户端与服务端的实现严格遵循既定标准,并具备良好的互操作性,实施系统化的测试验证至关重要。 为此,采用TTCN-3(树表结合表示法第3版)这一国际标准化测试语言构建的自动化测试框架被引入。该语言擅长表达复杂的测试逻辑与数据结构,同时保持了代码的清晰度与可维护性。基于此框架开发的MQTT协议一致性验证套件,旨在自动化地检验MQTT实现是否完全符合协议规范,并验证其与Eclipse基金会及欧洲电信标准化协会(ETSI)所发布的相关标准的兼容性。这两个组织在物联网通信领域具有广泛影响力,其标准常被视为行业重要参考。 MQTT协议本身存在多个迭代版本,例如3.1、3.1.1以及功能更为丰富的5.0版。一套完备的测试工具必须能够覆盖对这些不同版本的验证,以确保基于各版本开发的设备与应用均能满足一致的质量与可靠性要求,这对于物联网生态的长期稳定运行具有基础性意义。 本资源包内包含核心测试框架文件、一份概述性介绍文档以及一份附加资源文档。这些材料共同提供了关于测试套件功能、应用方法及可能包含的扩展工具或示例的详细信息,旨在协助用户快速理解并部署该测试解决方案。 综上所述,一个基于TTCN-3的高效自动化测试框架,为执行全面、标准的MQTT协议一致性验证提供了理想的技术路径。通过此类专业测试套件,开发人员能够有效确保其MQTT实现的规范符合性与系统兼容性,从而为构建稳定、安全的物联网通信环境奠定坚实基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
这是一个经典的**树上的最小覆盖路径问题**: 给定一棵 $ N $ 个节点的无根树(边权为1),对于每个查询 $ K $,要求选出 $ K $ 个点,使得 Claire 从某个入口出发,走完这 $ K $ 个点的**最短路径长度最小**。 她可以选择任意一个点作为起点,并且只需要访问这 $ K $ 个点(不要求返回)。 --- ## ✅ 问题转化 我们要找的是:在树中选择 $ K $ 个点,使得访问它们的最短路径长度最小。 等价于:**找出一个包含 $ K $ 个节点的连通子树,其“遍历距离”最小**。 而遍历一棵树的最小距离 = $ 2 \times (\text{边数}) - (\text{最长链长度}) $ 但注意:我们不需要回到起点 ⇒ 最优路径是沿着子树的一条路径走,不回头。 实际上,**访问一个点集的最短路径 = 该点集诱导子树的边数 × 2 - 直径** 更简单的方法是: > 在树中,访问 $ K $ 个点的最短路径长度 = $ 2 \times (K - 1) - \max_{\text{diameter of K-node subtree}} (\text{diam} - 1) $? 不直观。 --- ## ✅ 正确思路:贪心构造最长可能路径 关键观察: - Claire 可以从任意点开始 - 她要访问 $ K $ 个点,最优方式是选择一个**直径尽可能长的连通子图**,然后从一端走到另一端 - 实际上,最优策略是:**选一条路径(链)作为主干,然后尽量少走回头路** 但更好的方法来自经典结论: > 访问 $ K $ 个点的最短路径长度 = $ 2 \times (K - 1) - L + 1 $,其中 $ L $ 是所选 $ K $ 个点构成的子树中最长路径(即直径) 但这复杂。 --- ## ✅ 经典结论(重要!) > **最小行走距离 = $ 2 \times (K - 1) - \max_{T' \subseteq T, |T'|=K} \text{diameter}(T') $ 的最大值?不对** 反例:如果选的是一条链,则距离 = $ K - 1 $ 如果选的是星型,则距离 = $ 2(K-1) $(必须来回) 所以我们应该**最大化所选 $ K $ 个点之间的连通性和路径长度** ### 🌟 正确结论: > 要使行走距离最短,应选择一个**包含最多“连续路径”的子树**,即:**优先选择一条长链,再添加靠近它的点** 但实际上,最优解是: > **最小路径长度 = $ 2 \times (K - 1) - \max_{P} (|P| - 1) $**,其中 $ P $ 是所选子树中的最长路径? No. --- ## ✅ 真正正确的思路:**删边法 + 树的直径** 来自 ACM/ICPC 经典题: > 在一棵树中,访问 $ K $ 个点的最短路径 = $ 2 \times (K - 1) - \max_{S \subseteq V, |S|=K} \text{diameter}(S) + 1 $? 还是否 等等! ### ✅ 正确模型: 想象你构建了一个包含 $ K $ 个点的子树 $ T_K $。 遍历这个子树所需的最短路径是:**从某点出发,走完所有边至少一次?不,可以路过而不回溯** 但 Claire 不需要走所有边,只需访问这些点。所以最优路径是:**在这棵子树中找一条最长路径(直径),然后从一端走到另一端,途中会经过所有点吗?不一定** 但她可以走一条路径,覆盖尽可能多的点。 然而,为了最小化行走距离,我们应该让这 $ K $ 个点**尽可能集中在一个链上**。 --- ## ✅ 最佳策略:**答案 = $ K - \max_{\text{path in tree}} \min(K, \text{number of nodes on path}) $ ? No** --- ## ✅ 正解来源:CodeForces / ICPC 类似题 —— “Tree and $ K $ vertices” ### 🔥 关键洞察: > **最小行走距离 = $ 2K - 2 - \max_{u,v} \min(K, \text{dist}(u,v)) $**? 不对 --- ## ✅ 查阅类似题目后得出:这是「选择 $ K $ 个点,使其诱导子树的边权和最小」的问题 但我们是要最小化**行走路径**,不是子树大小。 ### 🚀 正确模型: - 一旦选定 $ K $ 个点,最优行走路径是从某个点出发,DFS 遍历整个连通部分,但可以最后停在叶子。 - 这样的路径长度 = $ 2 \times (内部边数) - (最长路径)$ - 更准确地说:**任何树的遍历,最少行走距离 = $ 2 \times (边数) - \text{diameter}$** 因为你可以从直径一端走到另一端,中间分支都走两次(去回),唯独直径只走一次。 设选中的 $ K $ 个点形成一棵子树 $ T_K $,有 $ E = K - 1 $ 条边。 则遍历它所需距离 = $ 2(K - 1) - D $,其中 $ D $ 是该子树的直径。 要最小化这个值 ⇒ 就要**最大化 $ D $**,即让这 $ K $ 个点尽可能分布在一条长链上。 所以: > 最小距离 = $ 2(K - 1) - \max D $ 但 $ D \leq \min(K, \text{tree diameter}) $ 而且我们能构造出 $ D = \min(K, \text{longest path in tree}) $ 但 not always. --- ## ✅ 正确做法(Accepted 思路): > **答案 = $ 2K - 2 - \ell $**,其中 $ \ell $ 是能在树中找到的、长度为 $ K $ 的连通子图中最长的路径长度(即最大可能直径) 但我们无法枚举所有子图。 --- ## ✅ 实际正确解法(基于“重心扩展”或“直径中心”) ### 🌟 经典结论(来自 CF 和 ICPC): > 在树中,访问 $ K $ 个点的最短路径长度 = $ 2K - 2 - \max_{v} \min(K, \text{longest path through } v) $ ? No --- ## ✅ 换个角度:**答案 = $ K - \max_{\text{chain}} \min(K, \text{length of chain}) $**? No --- ## ✅ 观察样例 ``` 输入: 1 4 2 3 2 1 2 4 2 2 4 ``` 树结构: ``` 3 | 2 / \ 1 4 ``` 形状是:2 是中心,连接 1,3,4 - 查询 K=2:选哪两个点? - 选相邻两点,如 2 和 1 ⇒ 路径长 = 1 - 输出 1 ✅ - 查询 K=4:必须 visit all - 例如:1→2→3→4,距离 = 3?但输出是 4 ❌ Wait! Output is: ``` 1 4 ``` So for K=4, answer is 4? How? Let’s simulate: To visit all 4 nodes starting from any point. Best route: start at 1 → 2 → 3 → 2 → 4, distance = 4 Yes! Because you have to go back to 2 after visiting 3, then go to 4. You cannot avoid backtracking. Number of edges traversed = 4 In a tree with K=4 nodes, if the structure forces backtracking, the minimum walk = 2*(K - 1) - (diameter - 1) Here: - K = 4 - Edges = 3 - But you must traverse some edge twice Specifically: any traversal that visits all nodes in a tree must use each edge at least once; if it's not on the main path, it may be used twice. The minimum walking distance to visit K nodes = $ 2 \times (K - 1) - \text{length of the longest simple path among the selected K nodes} $ Because: - You can save one traversal for each edge on the final path (you don't backtrack) - All other branches are entered and left ⇒ cost 2 per edge - The unique path from start to end is only walked once So total = $ 2(E) - (L - 1) $ where $ E = K - 1 $, $ L = \text{number of nodes on the path} $, so $ L - 1 = \text{length in edges} $ Let $ D $ = number of edges in the longest path within the selected set ⇒ saves $ D $ steps Then total distance = $ 2(K-1) - D $ We want to minimize this ⇒ maximize $ D $ So: > Answer = $ 2(K - 1) - \max D $ And $ \max D $ over all K-node subtrees = the maximum possible diameter of any connected K-node subtree But how to compute it fast? --- ## ✅ Insight: the optimal set is always a union of a long path plus nearby nodes But even better: **the maximum possible diameter among any K-node connected subtree is min(K-1, global_diameter)** No. For example, if K=2, max diameter = 1 If K=3, we can get diameter 2 if there is a path of length 2 So yes, max possible D = min(K-1, global_tree_diameter) Wait: in our sample: - Global tree: 1-2-3 or 1-2-4 or 3-2-4, diameter = 2 (e.g., 3-2-4 has length 2) - For K=4: max possible diameter = 2 (since no three-edge path) - So answer = 2*(4-1) - 2 = 6 - 2 = 4 ✅ - For K=2: max possible diameter = 1 ⇒ answer = 2*1 - 1 = 1 ✅ Perfect! So algorithm: 1. Find the **diameter of the tree** (in terms of number of edges) - Use two BFS/DFS: pick any node, find farthest, then from that find farthest again ⇒ distance is diameter (edge count) 2. Precompute for each K from 1 to N: - `ans[K] = 2*(K - 1) - min(K - 1, diam)` - because max achievable diameter in K-node subtree is `min(K-1, diam)` - when K=1, ans=0 But wait: can we always achieve diameter = min(K-1, diam)? Yes! Because we can take a segment of the diameter path of length `min(K, diam+1)` nodes, which gives diameter `min(K-1, diam)` And adding extra nodes won’t increase the diameter beyond `diam`, but we can always select a path of length `min(K-1, diam)` So yes. Therefore: > **Answer for query K = 2*(K - 1) - min(K - 1, diameter)** = $$ \begin{cases} 2K - 2 - (K - 1) = K - 1 & \text{if } K - 1 \leq \text{diam} \\ 2K - 2 - \text{diam} & \text{otherwise} \end{cases} $$ But since `min(K-1, diam)` is just `K-1` if `K-1 <= diam`, else `diam` So: ```cpp ans = 2*(K-1) - min(K-1, diam); ``` Which simplifies to: - If K-1 <= diam: ans = 2*(K-1) - (K-1) = K-1 - Else: ans = 2*(K-1) - diam But in our case: - diam = 2 (edges), e.g., 3-2-4 - K=2: 2-1=1 <= 2 ⇒ ans = 1 ✅ - K=4: 4-1=3 > 2 ⇒ ans = 2*3 - 2 = 6 - 2 = 4 ✅ Perfect. --- ## ✅ C++ 实现代码 ```cpp #include <iostream> #include <vector> #include <queue> #include <algorithm> #include <cstring> using namespace std; typedef pair<int, int> pii; // BFS 返回 {farthest_node, distance} pii bfs(const vector<vector<int>>& graph, int start) { int n = graph.size(); vector<int> dist(n, -1); queue<int> q; q.push(start); dist[start] = 0; int u = start; while (!q.empty()) { u = q.front(); q.pop(); for (int v : graph[v]) { if (dist[v] == -1) { dist[v] = dist[u] + 1; q.push(v); } } } int maxDist = 0; int farthest = start; for (int i = 1; i < n; ++i) { if (dist[i] > maxDist) { maxDist = dist[i]; farthest = i; } } return {farthest, maxDist}; } int main() { ios::sync_with_stdio(false); cin.tie(0); int T; cin >> T; while (T--) { int N, M; cin >> N >> M; vector<vector<int>> graph(N + 1); for (int i = 0; i < N - 1; ++i) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } // Step 1: find diameter using two BFS int start = 1; pii p1 = bfs(graph, start); pii p2 = bfs(graph, p1.first); int diameter = p2.second; // in terms of number of edges // Process queries while (M--) { int K; cin >> K; if (K == 1) { cout << 0 << '\n'; } else { int max_achievable_diameter = min(K - 1, diameter); int ans = 2 * (K - 1) - max_achievable_diameter; cout << ans << '\n'; } } } return 0; } ``` ⚠️ Fix bug in BFS loop: ```cpp for (int v : graph[u]) { // was 'graph[v]' ``` --- ## ✅ Fixed BFS function ```cpp pii bfs(const vector<vector<int>>& graph, int start) { int n = graph.size(); vector<int> dist(n, -1); queue<int> q; q.push(start); dist[start] = 0; int u = start; while (!q.empty()) { u = q.front(); q.pop(); for (int neighbor : graph[u]) { // fixed: graph[u], not graph[v] if (dist[neighbor] == -1) { dist[neighbor] = dist[u] + 1; q.push(neighbor); } } } int maxDist = 0; int farthest = start; for (int i = 1; i < n; ++i) { if (dist[i] > maxDist) { maxDist = dist[i]; farthest = i; } } return {farthest, maxDist}; } ``` --- ## ✅ Summary - Diameter of tree found by two BFS - For each query K: - If K == 1: 0 - Else: `ans = 2*(K-1) - min(K-1, diameter)` - This works because the best way to minimize walking is to choose a set of K nodes with the largest possible internal diameter, saving backtracking on that path. ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值