AcWing 730. 机器人跳跃问题 (二分)

AcWing 730. 机器人跳跃问题

思路:

  • 由题意可以推出从当前位置跳到下一个位置时,下一个位置的能量值一定为: 2 ∗ E 当 前 − H 下 一 位 置 2*E_{当前}-H_{下一位置} 2EH
  • 由简单的数学归纳可以知道,当 E 0 E_0 E0 满足题意的最小初始能量时,任何大于 E 0 E_0 E0 的初始能量也满足题意,任何小于 E 0 E_0 E0 的初始能量就不再满足题意了
  • 从上面的结论可以看出具有二段性,其中二段性的分界点即为满足题意的最小初始能量 E 0 E_0 E0,因此该题可以用二分法
  • 二段性:左半段的初始E无法让机器人每次跳跃的位置的能量 > 0,右半段的初始E可以让机器人每次跳跃的位置能量 >= 0
  • 分界点:最小的初始E能让机器人每次跳跃的位置能量 >= 0
public class Main {
    int N;
    int[] H;
    Scanner s = new Scanner(System.in);
    
    void run() {
        N = s.nextInt();
        H = new int[N + 1];
        for (int i = 1; i <= N; i++) {
            H[i] = s.nextInt();
       }

        int l = 0, r = 100000;
        while (l < r) {
            
            int mid = (r + l) / 2;
            if (isValid(mid)) r = mid;
            else l = mid + 1;
            
        }
        System.out.println(r);
    }

    boolean isValid(int e) {
        BigInteger bi = new BigInteger(String.valueOf(e));

        for (int i = 1; i < H.length; i++) {
            bi = bi.multiply(new BigInteger(String.valueOf(2)));
            bi = bi.subtract(new BigInteger(String.valueOf(H[i])));
            if (bi.compareTo(new BigInteger(String.valueOf(0))) < 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        new Main().run();
    }
}

细节问题:

对于isValid方法,如果直接使用e = 2 * e - H[i]很可能会爆int(long也不行),所以这里使用了大数来处理

优化:

只要初始能量 e >= H[i] 的最大可能高度,由递推式子 2 ∗ E 当 前 − H 下 一 位 置 2*E_{当前}-H_{下一位置} 2EH 可以推出其后续的每次跳跃的位置的能量一定 > 0,所以该条件下就直接return ture,不用再继续递推导致爆int

boolean isValid(int e) {
    for (int i = 1; i < H.length; i++) {
		e = 2 * e - H[i];
		// 如果不加该判断会爆int
		if(e >= 1e5) return true;
        if (e < 0) return false;
    }
    return true;
}

你可能感兴趣的:(算法,#,二分法)