题解:学而思编程 蚂蚁
【题目来源】
学而思编程:蚂蚁
【题目描述】
有 \(n\) 蚂蚁在长度为 \(L\) 单位的木棍上,每只蚂蚁都有一个初始的位置和初始朝向(任意两只蚂蚁的初始位置不同),每只蚂蚁都以每秒一个单位的速度向前移动。其中一部分蚂蚁向左移动,其他蚂蚁向右移动。
当两只向不同方向移动的蚂蚁在某个点相遇时,它们会同时改变移动方向并继续移动。假设更改方向不会花费任何额外时间。
而当蚂蚁在某一时刻 \(t\) 到达木板的一端时,它立即从木板上掉下来,初始时刻 \(t=0\)。请你用编程实现:最后一只蚂蚁从木棍上掉下来的时刻。
【输入】
输入有 \(n+1\) 行,第 \(1\) 行两个正整数 \(n,L\);
第 \(2\) 行到第 \(n+1\) 行,每行两个整数 \(x_i,d_i\),\(x_i\) 表示第 \(i\) 只蚂蚁的初始位置,\(d_i\) 表示第 \(i\) 只蚂蚁的初始朝向,其中 \(d_i=0\) 表示第 \(i\) 只蚂蚁初始朝向向左,\(d_i=1\) 表示第 \(i\) 只蚂蚁初始朝向向右。
【输出】
输出一个整数 \(t\),最后一只蚂蚁从木棍上掉下来的时刻。
【输入样例】
4 4
0 1
1 1
3 0
4 0
【输出样例】
4
【核心思想】
-
问题分析:给定 \(n\) 只蚂蚁在长度为 \(L\) 的木棍上,每只蚂蚁初始位置为 \(x_i\),朝向 \(d_i\)(\(0\) 向左,\(1\) 向右),速度均为 \(1\) 单位/秒。两只蚂蚁相遇时改变方向,求最后一只蚂蚁掉落的时刻。这是一个碰撞等效转化问题,关键在于发现蚂蚁碰撞后改变方向等价于"穿透"继续直行。
-
算法选择:
- 穿透等效法:将碰撞后掉头等效为两只蚂蚁互相穿透继续原方向移动,因为蚂蚁不可区分,碰撞不改变蚂蚁集合的运动状态
- 极值统计:每只蚂蚁的掉落时间只取决于其到对应端点的距离,与碰撞无关
-
关键步骤:
- 读取输入:读取 \(n\)(蚂蚁数量)、\(L\)(木棍长度)
- 初始化:\(ans = 0\)(记录最大掉落时间)
- 逐只处理(循环 \(n\) 次):
- 读取 \(x_i\)(位置)、\(d_i\)(朝向)
- 计算掉落时间:
- 若 \(d_i = 0\)(向左):掉落时间 \(t_i = x_i\)(到左端点距离)
- 若 \(d_i = 1\)(向右):掉落时间 \(t_i = L - x_i\)(到右端点距离)
- 更新最大值:若 \(t_i > ans\),则 \(ans \leftarrow t_i\)
- 输出结果:\(ans\) 即为最后一只蚂蚁的掉落时刻
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),只需遍历 \(n\) 只蚂蚁各一次
- 空间复杂度:\(O(1)\),仅使用 \(ans\) 变量,无需存储蚂蚁信息
-
穿透等效的核心思想:
- 碰撞不变性:两只蚂蚁碰撞后掉头,与它们互相穿透继续直行,在宏观效果上等价。因为蚂蚁完全相同,无法区分哪只是哪只,碰撞只是交换了两只蚂蚁的"身份"
- 问题降维:将复杂的碰撞交互问题转化为简单的单蚂蚁运动问题,每只蚂蚁独立计算到端点的距离即可
- 方向分离:向左的蚂蚁只关心到左端点距离 \(x_i\),向右的蚂蚁只关心到右端点距离 \(L - x_i\),两者互不干扰
- 全局最优:最后一只掉落的时间是所有蚂蚁掉落时间的最大值,即 \(\max(\max_{d_i=0} x_i, \max_{d_i=1} (L - x_i))\)
- 适用于不可区分粒子碰撞、运动等效转化类问题
【解题思路】

【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 输入n(物品数量)和L(总长度)
int n, L;
cin >> n >> L;
// 初始化最大距离ans为0
int ans = 0;
// 遍历每个物品
for (int i = 1; i <= n; i++)
{
// 输入物品的位置x和方向d
int x, d;
cin >> x >> d;
// 根据物品方向处理
if (d == 0)
{
// 方向为0(向左):最大距离就是x本身
if (x > ans)
{
ans = x;
}
}
else
{
// 方向为1(向右):最大距离是L-x
if (L - x > ans)
{
ans = L - x;
}
}
}
// 输出所有物品中的最大距离
cout << ans;
return 0;
}
【运行结果】
4 4
0 1
1 1
3 0
4 0
4
浙公网安备 33010602011771号