题目:
一根长度为L厘米的木棍上有n只蚂蚁,每只蚂蚁要么朝左爬,要么朝右爬,速度为1cm/s。当两只蚂蚁相遇时,两者同时调头,如果蚂蚁爬超出木棍两端则掉下。给出每只蚂蚁初始的位置和朝向,计算T秒之后每只蚂蚁的位置。
【Input】
输入的第一行为数据组数。之后每组数据:第一行为三个正整数L,T,n(0<=n<=10000);以下n行每行输入一个正整数x和一个特定字母(L或R),描述一只蚂蚁的初始状态,其中,整数x为蚂蚁距离木棍左端的距离,字母表示初始朝向(L左R右)。
【Output】
对于每组数据,输出n行,按顺序输出每只蚂蚁的位置和朝向(Turning表示正好相遇)。在T秒及之前掉下木棍的蚂蚁输出Fell off。
【Sample Input】
2 10 1 4 1 R 5 R 3 L 10 R 10 2 3 4 R 5 L 8 R
【Sample Output】
2 Turning 6 R 2 Turning Fell off 3 L 6 R 10 R
分析:
首先排除模拟,因为碰头的操作次数可能会非常多,而有多组数据,时间上会有极大的浪费。既然模拟不好,那就想办法从模拟过程中找到特点和规律替代模拟。
在纸上画一横轴,描几个点表示蚂蚁。当蚂蚁碰头时,它们的方向会发生变化,而变化后又会碰头其他蚂蚁。想要描述整个T秒内方向的变化显然比较复杂。那如何能规避方向的问题呢?
假设横轴上两黑点碰头,一黑点向前,另一个向后。都是黑点,它们的运动就像路过对方,而没有碰头一样......假设所有蚂蚁都没有名字,那么因此,蚂蚁的运动就可以忽略碰头了。因为从过程上来看,假设一蚂蚁从(1, R),也即位置1,向右,两秒后没碰头变为(3,R)。如果忽略身份的话那么不管中间多少只蚂蚁碰了多少次头,总有一只蚂蚁会达到(3,R),因为忽略身份后所有蚂蚁都是一样的,他们之间就没有所谓的“碰头”了。
现在问题就转到了身份name上。有了身份差别便有了位置次序,先创建两个结构体数组begin,end;begin储存原始信息,end储存碰头不变向的运动后信息,对两者排序,保证在木棍上的位置是升序的。因为碰到即转向,蚂蚁的位置次序(身份序号)在运动前后是不变的,这样就把位置次序和输入顺序联系了起来。而后创建int型realName数组储存位置次序与输入顺序的关系。通过运动前左端排序第i的蚂蚁的输入次序name,得到不碰头运算后原次序第i个蚂蚁的当前排序,再.place即可得到原次序第i蚂蚁的位置,这样便可有序输出。
例:
输入: 1 10 3 4 8 R 2 L 10 L 4 R ← → → ← 方向 1 3 0 2 编号 ------·-------·------------·-------· 木棍 length = 10 2 4 8 10 位置 结构体数组begin之中存储的身份: {0, 1, 2, 3};位置:{2, 0, 3, 1}; 对数组begin根据place排序:身份: {1, 3, 0, 2};位置:{0, 1, 2, 3}; T秒后: → ← 方向 1 (fell) 3,0 2 (fell) 编号 . ----------------------·----------- · 木棍 length = 10 -1 7 11 位置 end数组:身份:{1, 3, 0, 2};对应T秒前begin,无变化。
代码:
package Test; import org.jetbrains.annotations.NotNull; import java.util.*; /** * @deprecated Piotr`s Ants, UVa 10881 * @author WitMoy * @version V1.8 * @date : 2022-07-28 16:31 */ public class PiotrAnts { private static Scanner in = new Scanner(System.in); public static void main(String[] args) { int times = in.nextInt(); while(times-- > 0){ int L, T, n; L = in.nextInt(); T = in.nextInt(); n = in.nextInt(); //创建Ants数组 Ants[] begin = new Ants[n], end = new Ants[n]; for(int i = 0; i < n; i++){ begin[i] = new Ants(); end[i] = new Ants(); } //输入数据 for(int i = 0; i < n; i++){ int place = in.nextInt(); String direction = in.next(); boolean t = Objects.equals(direction, "L"); int positive = 1; if(t){ positive *= -1; } begin[i].setPlace(place); begin[i].setDirection(direction); begin[i].setName(i); //计算“路过”的最终位置 end[i].setPlace(place + T * positive); end[i].setDirection(direction); } //为Java自带的sort写排序规则,也可以自己写排序函数 Comparator<Ants> myComparator = new MyComparator(); //对运动前后的蚂蚁按照位置从左向右排序 Arrays.sort(begin, myComparator); Arrays.sort(end, myComparator); //通过位置次序的不变性联系原输出次序 int[] realPlace = new int[n]; for(int i = 0; i < n; i++){ /*因为位置次序不变,原来排第一的在之后还在第一,而它 的输出次序为begin[].getName();*/ //次序为begin[i].getName()的排第i realPlace[begin[i].getName()] = i; } //先不管身份,更新每个节点的输出状态 for(int i = 0; i < n; i++){ if(end[i].getPlace() < 0 || end[i].getPlace() > L){ end[i].setDirection("Fell off"); } else if(i < n - 1 && end[i].getPlace() == end[i + 1].getPlace()){ end[i].setDirection("Turning"); end[i + 1].setDirection("Turning"); } } //输出 for(int i = 0; i < n; i++){ //原输出次序为i的排序为originalOrder int NowOrder = realPlace[i]; int place = end[NowOrder].getPlace(); if(place >= 0 && place <= L){ System.out.print(place + " "); } System.out.println(end[NowOrder].getDirection()); } System.out.println(); } } } class Ants{ private int place; private String direction; private int name; public int getName() { return name; } public void setName(int name) { this.name = name; } public String getDirection() { return direction; } public void setDirection(String direction) { this.direction = direction; } public int getPlace() { return place; } public void setPlace(int place) { this.place = place; } } class MyComparator implements Comparator<Ants>{ public int compare(@NotNull Ants a, @NotNull Ants b) { return a.getPlace() - b.getPlace(); } } /*测试数据 2 10 1 4 1 R 5 R 3 L 10 R 10 2 3 4 R 5 L 8 R 2 Turning 6 R 2 Turning Fell off 3 L 6 R 10 R * */