洛谷P2678 [NOIP2015 提高组] 跳石头
题目练习:
思路:
题目要求找出最短跳跃距离
暴力,假设距离是 1 , 2 , 3, 4, 5, …
判断函数:
bool is_jump_max(int max,int nums[],int len,int k){
int mark=0;//前一块石头的下标
for(int i=1;i<=len;i++){//从第一块石头开始遍历
if(nums[i]-nums[mark]<max) {
if(k==0){
return false;
}
k--;
}else{
mark=i;
}
}
return true;
}
如果距离能够符合移动 k 块的条件 就返回 true 否则返回 false
主函数:
int main(){
int L,N,M;
cin>>L>>N>>M;
int nums[50010]={0};
for(int i=1;i<=N;i++) cin>>nums[i];
for(int i=1;;i++){
// i 从 1 开始遍历,找到第一个不符合的然后跳出 直接输出 i 减一即可 因为小于这个不符合的之前的一定都符合
if(!is_jump_max(i,nums,N,M)) {
cout<<i-1<<endl;
break;
}
}
return 0;
}
最后结果为 90 分
优化程序
不难发现这个题目的结果一定有一个分界点 x ,小于等于 x 的值都符合答案
所以我们可以以二分的形式来查找答案,也就是那个分界点
先定义一个左端点 l 为o ,右端点 r 为最大长度 (最差情况,一步跨过去)
每次判断那个中间节点 mid = (l+r)/2 是不是再区间内
在区间内的话我们就移动左端点
不在的话我们就移动右端点
最后右端点始终会停留再 x (分界点) 的位置上
所以我们主函数的可以改成:
int main(){
int L,N,M;
cin>>L>>N>>M;
int nums[50010]={0};
for(int i=1;i<=N;i++) cin>>nums[i];
int l=1,r=L;
while(l<=r){
int mid=(l+r)/2;
if(is_jump_max(mid,nums,N,M)){
l=mid+1;
}else{
r=mid-1;
}
}
cout<<r<<endl;
return 0;
}
最终结果,满分通过
代码:
#include <bits/stdc++.h>
using namespace std;
bool is_jump_max(int max,int nums[],int len,int k){
int mark=0;//前一块石头的下标
for(int i=1;i<=len;i++){//从第一块石头开始遍历
if(nums[i]-nums[mark]<max) {
if(k==0){
return false;
}
k--;
}else{
mark=i;
}
}
return true;
}
int main(){
int L,N,M;
cin>>L>>N>>M;
int nums[50010]={0};
for(int i=1;i<=N;i++) cin>>nums[i];
int l=1,r=L;
while(l<=r){
int mid=(l+r)/2;
if(is_jump_max(mid,nums,N,M)){
l=mid+1;
}else{
r=mid-1;
}
}
cout<<r<<endl;
return 0;
}