poj 3258 二分 过河

题意:给出河宽,石头数,还有最多可以删去石头的数量m。意思是你要过河,但是你必须踩着石头过河,在这个过程中你可以删去一些石头,最多可以删m个,求跳跃的过程中最小的距离中的最大距离.

思路:区间是0~L ,然后二分mid 代表了最小距离,如果这个距离满足是最小距离(ok函数模拟删除石头的过程)left + 1,否则right - 1,逐渐逼近答案

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 50010;
__int64 rock[maxn];
__int64 L , n , m;
bool ok(__int64 mid) {
	int remove = 0;
	int i , pos = 0;
	for (i = 1 ; i <=n+1 ; i ++) {
		if (rock[i] - rock[pos] < mid) {//mid代表跳跃最小距离  比这个距离小的i 删去 
			remove ++;
			if (remove > m) return false;	
		} 
		else pos = i;	
	}	
	return true;
}
int main() {
	int i;
	while (scanf("%I64d %I64d %I64d",&L,&n,&m)!=EOF) {
		rock[0] = 0;
		for (i = 1 ; i <= n ; i ++) scanf("%I64d",&rock[i]);
		rock[n+1] = L;
		sort(&rock[1],&rock[n+2]);
		__int64 left = 0;
		__int64 right = L;	
		__int64 mid;
		int ans;
		while (left <= right) {
			mid = (left+right)>>1;	
			if (ok(mid)) {ans = mid ;left = mid + 1;}//为什么加个ans 就过 ? 跳出循环的条件 可以是left > right的原因么? 
			  										//因为最后如果是left == right 的时候 可能下一步是left = mid + 1,或者是
													//right = mid - 1;  所以 用一个变量来记录答案比较好 
			else {right = mid - 1;}
		}
		printf("%d\n",right);	
	}		
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值