POJ 3258 最小值最大化 二分搜索
题意:牛要到河对岸,在与河岸垂直的一条线上,河中有N块石头,给定河岸宽度L,以及每一块石头离牛所在河岸的距离,
现在去掉M块石头,要求去掉M块石头后,剩下的石头之间以及石头与河岸的最小距离的最大值。
首先去理解题意,去除一些石头之后,使得跳跃的最短距离是最大的,这个跳跃的距离一定是一个值而且一定小于总距离,同时我们可以知道的是,如果移除某几块石头,以某一最短距离跳跃都满足的话,小于这个最短距离的话一定都满足,大于这个最短距离便不一定,所以二分搜索的好处在于可以精准地通过之前的判断对下一次的范围进行锁定,进行判断,确保获得最大的最短距离。进行判断的时候我们可以通过不断地顺序试探,如果跳跃距离小于要求的最短距离,则需要将移除的石头加一。并且之后的距离就是将这块石头移除之后的距离,注意这里就有一个顺序。从前往后。我在做本题时主要对终点的那段距离抱有疑惑,其实终点那段虽然终点不能移除,但只要要移除的石头数小于等于n,就可以通过移除之前的石头实现。如果要移除n+1块石头那显然也不符合m<=n的要求。
难点两个:
1,二分搜索最短距离值
2,顺序的通过该值去判断删去一些石头是否满足(实际删去的石头数量和需要删除的数量),算距离时还要注意起点的变化。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define MAXN 50005 6 using namespace std; 7 int num[MAXN]; 8 int l,n,m; 9 bool solve(int dist){ 10 int ans=0,j=0; 11 for(int i = 1;i<= n+1 ; i++){ 12 if(num[i] - num[j]<dist){ 13 ans++; 14 } 15 else 16 { 17 j = i; 18 } 19 } 20 if(ans > m) 21 return false; 22 else 23 return true; 24 } 25 int main(){ 26 int i; 27 scanf("%d%d%d",&l,&n,&m); 28 num[0]=0; 29 for(i = 1; i <= n ; i++){ 30 scanf("%d",&num[i]); 31 } 32 sort(num,num+n+1); 33 num[n+1] = l; 34 int left = 0,right = l; 35 int mid = 0 ; 36 int val = l; 37 while(left<=right){ 38 mid = left + (right - left) / 2; 39 if(solve(mid)){ 40 val = mid ; 41 left = mid + 1; 42 } 43 else 44 right = mid - 1; 45 } 46 cout<<val<<endl; 47 return 0; 48 }