hdu2438---二分—>三分法

二分法
求具有单调函数中逼近求解某点的值,是求f(x)==y 时x的值是什么,通常来说y为0,但也不言定。特定:查找中我们由二分查找,在有序数组中查找特定元素的算法 排序中是二分排序,也就是快排,归并排序
二分查找适合有序的数组进行查找:

#include<iostream>
#define N 10
using namespace std;
int main()
{ 
  int a[N],front,end,mid,x,j;
  int a[N]={.....};//假设已排好序
  cin>>x;//s输入要查找的数x;
  front=0; end=N-1;//各指向首尾
  mid=(front+end)/2;
  while(front<end&&a[mid]!=x)
  {
    if(a[mid]<x) front=mid+1;
    if(a[mid]>x) end=mid-1;
    mid=(front+end)/2;
  }
  if(a[mid]!=x)//没找到
  else //找到了
}

时间复杂度
1.最坏情况查找最后一个元素(或者第一个元素)Master定理T(n)=T(n/2)+O(1)所以T(n)=O(log2n)
2.最好情况查找中间元素O(1)查找的元素即为中间元素(奇数长度数列的正中间,偶数长度数列的中间靠左的元素)
递归(其实差不多):

int BinSearch(int a[],int low,int high,int k )
{
   int mid;
   if(low<=high)
   {
      mid=(low+high)/2;
      if(a[mid]==k)
         return mid;
      if(a[mid]>k)
          return BinSearch(a,low,mid-1,k);
      else
           return BinSearch(a,mid+1,high,k);
   }
   return -1;
}

三分法:
我们都知道 二分查找 适用于单调函数中逼近求解某点的值。
如果遇到凸性或凹形函数时,可以用三分查找求那个凸点或凹点。
在这里插入图片描述
思路:通过不断缩小 [L,R] 的范围,无限逼近白点
做法:先取 [L,R] 的中点 mid,再取 [mid,R] 的中点 mmid,通过比较 f(mid) 与 f(mmid) 的大小来缩小范围。
当最后 L=R-1 时,再比较下这两个点的值,我们就找到了答案。
1、当 f(mid) > f(mmid) 的时候,我们可以断定 mmid 一定在白点的右边。
反证法:假设 mmid 在白点的左边,则 mid 也一定在白点的左边,又由 f(mid) > f(mmid) 可推出 mmid < mid,与已知矛盾,故假设不成立。
所以,此时可以将 R = mmid 来缩小范围。(通过分析得到的)
2、当 f(mid) < f(mmid) 的时候,我们可以断定 mid 一定在白点的左边。
反证法:假设 mid 在白点的右边,则 mmid 也一定在白点的右边,又由 f(mid) < f(mmid) 可推出 mid > mmid,与已知矛盾,故假设不成立。
同理,此时可以将 L = mid 来缩小范围。(通过分析得到的)
写法:
(先增后减型)

nt SanFen(int l,int r) //找凸点  差不多同上图
{  
    while(l < r-1)  
    {  
        int mid  = (l+r)/2;  
        int mmid = (mid+r)/2;  
        if( f(mid) > f(mmid) )  
        //右端移动到nmid处
            r = mmid;  
        //左端移动到mid处
        else  
            l = mid;  
    }  
    return f(l) > f(r) ? l : r;  
}  

(先减后增 易知与上面相反)

int SanFen(int l,int r) //找凸点  
{  
    while(l < r-1)  
    {  
        int mid  = (l+r)/2;  
        int mmid = (mid+r)/2;  
        if( f(mid) > f(mmid) )  
            l = mid;  
        else  
            r = mmid;  
    }  
    return f(l) > f(r) ? l : r;  
}  

为什么不能用二分法 因为如果想求一个抛物线的极大值的话,二分是不行的,因为二分其实就是缩短[L,R]区间,以mid为参考不断缩短区间距离。
如果用二分法,抛物线求极值的话,单纯二分没法确定极值点所在区间,
所以可以用三分
int mid = (l+r)/2;
int mmid = (mid+r)/2;
这样子根据图片就可以确定出三种情况 但是如果f(mid)==f(nmid)就令l=mid或r=nmid就行了

hdu2438
题意:给出一个90度转弯,对应宽窄x y如图所示,车对应宽窄l d如图所示,问你这辆车能否顺利通过
(这题知道三分法就比较好解决了 当时画了下图 求了方程只知道求这个方程极大值但不知道用程序怎么求。。)
在这里插入图片描述
大佬的图 直线比较好求,最终就是车翻转时在任意一点那个P点的横坐标的绝对值都不能大于Y,因为大于Y就撞上了,而且可以看出来P点跟蓝色直线的焦点横坐标绝对值先增大后减小,只要找极大值就行了,极大值小于等于Y,就能通过.

#include<iostream>
#include<cmath>
#include<stdio.h>

const double eps=1e-9;
double X,Y,L,D;
double PI=acos(-1.0);

double distance(double angle)
{
 return(-X+L*sin(angle)+D/cos(angle))/tan(angle);
}
int main()
{
   while(scanf("%lf %lf %lf %lf",&X,&Y,&L,&D)!=EOF)
   {
      if(X<D||Y<D) 
      {
        printf("no\n");
        continue;
      }
      double low=0,up=PI/2,mid,mmid;
      double dis1,dis2;
      while(true)
      {
               mid = (low + up) / 2;
               mmid = (mid + up) / 2;
               dis1 = distance(mid);
               dis2 = distance(mmid);
              if(dis1 > dis2) up = mmid;
              else low = mid;
              if(up - low < eps) break;
     }
     if(dis1)<=Y;
     printf("yes\n");
     else
     printf("no\n");
   }
}

From:
https://blog.csdn.net/huzujun/article/details/81187455?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://blog.csdn.net/u013761036/article/details/24588987

发布了19 篇原创文章 · 获赞 2 · 访问量 743

猜你喜欢

转载自blog.csdn.net/qq_45639157/article/details/104897573
今日推荐