“坠落的蚂蚁”思路
坠落的蚂蚁
https://www.nowcoder.com/practice/fdd6698014c340178a8b1f28ea5fadf8?tpId=40&tqId=21420&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking
关于“坠落的蚂蚁”这道题。一开始我尝试用追踪记录每一只蚂蚁的状态的方法解题,代码写了很长,最后只有40%的用例通过了检验,折腾了半天我也没发现到底错误在什么地方。代码:https://paste.ubuntu.com/p/q3GCtB2fw4/
这道题的一种简单思路如下:
1.静止蚂蚁的位置是固定不变的,即使蚂蚁相遇并发生了速度交换,永远都有一只蚂蚁处在初始静止蚂蚁A的位置。
2.假设A左侧蚂蚁都是向左的,右侧蚂蚁都是向右的,那么A必定不动,无法坠落。
3.左右移动的蚂蚁相遇时会交换速度,但从A的视角来看,是否交换速度对A的移动来说没有任何影响,可以看做两只蚂蚁互不影响继续前进。
4.综合2、3两点可以看出只有A左侧向右移动的蚂蚁和A右侧向左移动的蚂蚁会对A的移动产生影响。
5.当A左侧向右移动的蚂蚁和A右侧向左移动的蚂蚁数量相等时,A必定无法掉落。因为当A与距离其最近的LR(左侧向右)蚂蚁和RL(右侧向左)蚂蚁相遇之后,一定会回到静止状态。
6.当LR和RL蚂蚁不一样多时,A最终会继承较多一侧某蚂蚁的速度并且坠落,坠落时间等于该蚂蚁不受任何影响直线前进直至坠落的时间。
7.确定6中所指蚂蚁的方法,以LR蚂蚁较多为例:设RL蚂蚁数量为n,在LR蚂蚁中按初始位置从高到低数起,第n+1个LR蚂蚁即为所求蚂蚁。
启发:
当最终结果只关心某个元素时,可以考虑模糊其他元素的身份区别,只关心他们对所求元素的影响,将这种影响抽象出来作为解题思路可以大大降低编程难度。
追踪记录每个元素的方式不是不能用,在难以抽象的复杂情况下甚至可能会有更好的效果。但其缺点也很明显:当元素数量很多过程很长的时候,几乎不能用调试的方法找到其中细小的逻辑错误。这也是最终我只有40%通过率的原因。
代码:
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> using namespace std; struct ant{ int location; int velocity; }; bool Comp(ant a, ant b) { return a.location < b.location; } int main() { int n; while (scanf("%d", &n) != EOF) { ant Ants[n]; int Apos; for (int i = 0; i < n; i++) { scanf("%d %d", &Ants[i].location, &Ants[i].velocity); if (Ants[i].velocity == 0) { Apos = Ants[i].location; } } //输入结构体数组,记录A蚂蚁初始位置 vector<int>left, right; //定义两个容器分别存放A左侧向右蚂蚁,A右侧向左蚂蚁 sort(Ants, Ants + n, Comp); for (int i = 0; i < n; i++) { if (Ants[i].location < Apos && Ants[i].velocity == 1) { left.push_back(Ants[i].location); } if (Ants[i].location > Apos && Ants[i].velocity == -1) { right.push_back(Ants[i].location); } } //将LR和RL元素的位置加入容器中 if (left.size() == right.size()) { printf("Cannot fall!"); } else if (left.size() > right.size()) { printf("%d", 100 - left[left.size() - right.size() - 1]); } else { printf("%d", right[left.size()]); } } }