Java跳石头游戏 二分算法


1.Description

每逢过年,奶牛们玩跳石头游戏.这个游戏在一条笔直的河上进行.河上两个石头被作为起点和终点,它们之间的距离为L(1 ≤L <10’)、还有N(O<N<50000)个石头放置在这两个石头之间,每个石头距离起点都有一个独一无二的整数距离D;(0<D;<L).

游戏进行的时候,奶牛们从起点开始,依次跳到每一个相邻的石头上,最终到达终点.约翰对自己的奶牛很有信心.他每年都到场观看这奶牛们的游戏.今年,约翰终于不耐这个游戏的无聊,打算做一些手脚,好让别的农夫的奶牛出丑.他打算除掉M(0<M≤N)个石头,使任意两个石头间的最短距离变得尽量大.这样,别人家的奶牛就很有可能失蹄了.

请计算,采取最佳方案移除石头之后,最短距离是多少.注意,约翰不能移除起点和终点的石头.


2.Example

输入说明
第1行输入L,N,M.接下来N行,每行一个整数表示一个石头的位置.

输出说明
移除石头后的最短距离.

输入样例
25 5 22
14112117

输出样例
4

样例说明
移除之前,最短距离在位置2的石头和起点之间;移除位置2和位置14两个石头后,最短距离变成17和21或21和25之间的4.


3.Solution

先将石头的位置都记录在一个arraylist里(包括0位置和L位置)然后对list进行排序(使用二分需要一个有序序列)。
构造一个check函数来判断如果去掉所有间隔小于mid的石子后,去掉的石子数是不是比m少(里面使用了双指针的方法)。
在主函数中使用二分,找出正好去掉石子数等于mid时的间隔值。

public class Main {
    
        
    public static void main(String[] args) {
    
    
    	Scanner sc = new Scanner(System.in);
    	Long l = sc.nextLong();
    	int n = sc.nextInt();
    	int m = sc.nextInt();
    	List<Long> list = new ArrayList<Long>();
    	list.add((long) 0);
    	for(int i=0;i<n;i++) {
    
    
    		list.add(sc.nextLong());
    	}
    	list.add(l);
    	Collections.sort(list);//注意,这里不能直接list.sort
    	long left = 0,ans=0;
    	long right = l;
    	while(left<=right) {
    
    
    		long mid = (left+right)/2;
    		if(check(mid,list,m)) {
    
    //mid偏小
    			ans = mid;
    			left = mid+1;
    		}else {
    
    //mid偏大
    			right = mid-1;
    		}
    	}
    	System.out.println(ans);
    }
    
    public static boolean check(long mid,List<Long> list,int m) {
    
    
    //函数用于测试最短距离为mid时需要除去的石头数量
    	int left=0;
    	int tot=0;
    	for(int i=1;i<list.size();i++) {
    
    
    		if(list.get(i)-list.get(left)<mid) {
    
    
    			tot++;
    			if(tot>m) {
    
    
    				return false;//说明当前mid偏大
    			}
    		}else {
    
    
    			left = i;
    		}
    	}
    	return true;//说明当前小于或等于mid
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45736160/article/details/115086243