洛谷P2678 Java解法

题目出处点这里
在这里插入图片描述

思路:

形如求最小值的最大值以及求最大值的最小值都可以二分求解。
就像这道题,求最短的跳跃距离尽可能长(就是求最小值的最大值),注意到跳跃距离肯定在1至L之间,于是问题就变为在1~L之间求可行解的最大值,可行解就是跳跃距离的最小值,如果照着题目的思路思考,我们的思维可能会被只能移走M快岩石限制住,因此我们可以逆向思考,从结果入手:每次取1-L中mid的值,把每次的mid当作跳跃距离,然后判断跳跃距离为mid时需要移动的岩块sum为多少。如果sum<=M,那就说明这个最大值mid可以作为最大值,又因为1-L单调增,因此可能mid右边的也可以作为跳跃距离,所以往右边接着找;如果sum>M,那就说明这个最大值mid不能作为最大值,因为跳跃距离太大了,需要移动的石块sum也很多,因此我们得把跳跃距离弄小点,往mid左边寻找。
其中check()函数就是判断跳跃距离为mid时,需要跳过多少个石块

代码:

package binaryFindAndAnswer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class P2678 {

	static int L, N, M;
	static int[] arr;//存储每个石块的距离

	public static void main(String[] args) throws IOException {
		StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		st.nextToken();
		L = (int) st.nval;
		st.nextToken();
		N = (int) st.nval;
		st.nextToken();
		M = (int) st.nval;
		arr = new int[N + 2];// arr初始化,实际上N+2块石头(包括头尾两块)
		for (int i = 1; i <= N; i++) {
			st.nextToken();
			arr[i] = (int) st.nval;
		}
		arr[N + 1] = L;// 注意L才是终点
		int l = 0, r = L;
		// 开始对
//		int ans = 0;//也可以用ans记录mid
		while (l <= r) {
			int mid = (l + r) / 2;
			if (check(mid)) {//如果mid可以作为最大值,又因为l~r单调增,说明mid右边也有可能,因此l = mid + 1
				l = mid + 1;
//				ans = mid;
			}else {//如果不可以作为最大值,说明最大值在左边
				r = mid - 1;
			}
		}
		//输出当check(mid)为ture时的mid,此时mid=l-1
		System.out.println(l-1);
		//也可以用ans记录每次mid可行时的mid,并输出
//		System.out.println(ans);
	}

	public static boolean check(int mid) {
		int sum = 0,now = 0;//now代表现在所在的石块
		for (int i = 1; i < N+2; i++) {
			//因为此时我们假设此时的跳跃距离mid就是最大值,如果两个石头间隔小于mid那就说明可以拿走
			//如果两个石头距离大于mid,我们就根本跳不过去,所以这块石头不能拿掉,只好在下块石头接着跳
			if (arr[i] - arr[now] < mid) {//说明可以拿走
				sum++;
			}else {//说明不能拿走
				now = i;//那我们就到这一块石头上去继续判断
			}
		}
		if (sum > M) {//当要移的石块大于M
			return false;
		}else {//当要移动的石块小于等于M,说明此mid可行
			return true;
		}
	}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值