蚂蚁碰撞问题
作者:互联网
经典数学问题,在一根棍上多个蚂蚁,同时有不同的行走方向和相同的行走速度。如果蚂蚁碰撞则反向。
则整个过程可以等价为,蚂蚁之间不碰撞而穿过。
例题:Kick Start Round C 2022
https://codingcompetitions.withgoogle.com/kickstart/round/00000000008cb4d1/0000000000b209bc#analysis
题目为给定棍子,蚂蚁初始位置以及初始方向,求得蚂蚁的掉落顺序。
蚂蚁共N个,速度为1,棍长为L。
思路一:按时间模拟
构建全部蚂蚁的位置以及方向,按时间进行遍历,当两个蚂蚁到达同一位置时,变换方向(或者交换序号)。
时间复杂度O(LNlogN),适合L比较小。
思路二:按序号模拟。
因为蚂蚁碰撞可以等价于蚂蚁穿过。
假设每个蚂蚁带有一个ID,每次穿过都会交换ID,这样与原碰撞问题等价。
故可以先求出,每个蚂蚁之间相互碰撞的时间,作为一个事件。并将事件按时间排序。
按照事件发生的时间顺序交换蚂蚁的ID,则可以得到每个蚂蚁的最终ID。
同时在初始读入数据时,可以得到蚂蚁掉落的时间,按时间排序可以得到ID掉落的顺序。
时间复杂度O(N^2logN)
思路三:位置约束
由于蚂蚁之间的相对位置是不会改变的,故如果出现左侧掉落,则必为最左侧的蚂蚁掉落。右侧同理。
故可以按经典问题的思路,首先处理出全部蚂蚁掉落的时间。
掉落的时间以及在左侧还是右侧掉落,可以被视为一个掉落事件。
按时间顺序对掉落事件排序,按位置顺序对蚂蚁排序。
对掉落事件按时间进行处理,如果是左侧掉落,则移除最左侧的蚂蚁,如果是右侧,则移除最右侧的蚂蚁。
直到移去全部蚂蚁,可以得到蚂蚁的掉落顺序(注意左右同时掉落需要排序)。
时间复杂度O(NlogN)
代码如下
#include<bits/stdc++.h> using namespace std; int idx = 0; void YD() { int N, L; cin >> N >> L; vector<pair<double, int>> time_d(N); vector<pair<int, int>> p_index(N); for (int i = 0; i < N; i++) { int p, d; cin >> p >> d; p_index[i] = { p,i+1 }; double t = 0; if (d == 1) t = L - p; else t = p - 0; time_d[i] = { -t,d }; } cout << "Case #" << ++idx << ": "; sort(time_d.begin(), time_d.end()); sort(p_index.begin(), p_index.end()); int hh = 0, tt = N - 1; vector<pair<double, int>> time_index; while (time_d.size()) { int d = time_d.back().second; if (d == 1) { time_index.push_back({ -time_d.back().first,p_index[tt].second }); tt--; } else { time_index.push_back({ -time_d.back().first,p_index[hh].second }); hh++; } time_d.pop_back(); } sort(time_index.begin(), time_index.end()); for (auto &[t, i] : time_index) cout << i << ' '; cout << endl; } int main() { int T; cin >> T; while (T--) { YD(); } }View Code
标签:index,掉落,蚂蚁,int,碰撞,back,问题,time 来源: https://www.cnblogs.com/ydUESTC/p/16314557.html