why

数学问题

how

以第一只蚂蚁作为出发点,按照左右两边区间的形式来分析其他蚂蚁可能发生的所有情况

题目

一个木头上有很多蚂蚁,有一只蚂蚁必感冒,蚂蚁碰头就会调头,如果有一只感冒,在碰头的时候就会传染给另一只。输入n个蚂蚁,正数代表右方向,负数代表左方向,大小代表蚂蚁所在位置(具体左端点大小)。

分析一下

分析一

这里有一个理论基础,调头的我们不考虑方向,因为方向不影响蚂蚁的状态,我们把状态变了,具体是哪只蚂蚁调头了,并不影响结果,所以我们直接想象成,它改了状态然后接着走了,不调头。

分析二

第一只蚂蚁往右走
【右区间】
往左走,必然感染
往右走,必然不会感染
【左区间】
往左走,必然不会感染
往右走
1.如果右区间存在往左走的蚂蚁,必然会感染。
2.如果右区间不存在往左走的,必然不会感染。
如果第一只蚂蚁往左走。。。。

解析成代码

计数
左边向右走的,右边向左走的,都有可能是被感染蚂蚁。用大于号可以判断它的方向,和第一个数比大小可以知道该蚂蚁是在右区间还是左区间
判定
如果蚂蚁向右边走,并且右边区间没有向左走的蚂蚁。则感染数为1
如果蚂蚁向左边走,并且左边区间没有向右走的蚂蚁,则感染数为1
否则,感染数为【左边往右】走的,和【右边往左】走的总数
注意:在代码中左区间往右走的,我们也计为感染,因为它虽然是有判定条件,但是仔细看会发现判定条件其实是依赖于右区间往左走的。所以不管我们怎么计数,最后我们只需要确定右区间往左走不为0,那么计数就是有效的。

  1. import java.util.Scanner;
  2. public class AntInfection {
  3. static int[] nums;
  4. static int left;
  5. static int right;
  6. public static int checkCount() {
  7. for (int i = 1; i < nums.length; i++) {
  8. /*右区间往左走的*/
  9. if (Math.abs(nums[i]) > Math.abs(nums[0]) && nums[i] < 0) {
  10. left++;
  11. }
  12. /*左区间往右走的*/
  13. if (Math.abs(nums[i]) < Math.abs(nums[0])&& nums[i] > 0) {
  14. right++;
  15. }
  16. }
  17. if ((nums[0] > 0 && left==0)||(nums[0] < 0 && right == 0)) {
  18. return 1;
  19. }else{
  20. return left+right+1;
  21. }
  22. }
  23. public static void main(String[] args) {
  24. Scanner sc = new Scanner(System.in);
  25. int numsLength = sc.nextInt();
  26. nums = new int[numsLength];
  27. for (int i = 0; i < numsLength; i++) {
  28. nums[i] = sc.nextInt();
  29. }
  30. int result = checkCount();
  31. System.out.println(result);
  32. }
  33. }

易错点
在判定条件中比较大小的时候需要转换成绝对值比较。Math.abs( )

总结

左右 <—-> 右左(左区间往右走,右区间往左走,他们的发生是存在依赖的)
如果感染蚂蚁是左走,左右的为0,则感染数为1,
如果感染蚂蚁是右走,右左的为0,则感染数为1
其他情况,则左右右左都算数