三分入门HihoCoder - 1142+HDU2899

三分·三分求极值.

描述

这一次我们就简单一点了,题目在此:

在这里插入图片描述

在直角坐标系中有一条抛物线y=ax^2+bx+c和一个点P(x,y),求点P到抛物线的最短距离d。

提示:三分法

在之前的几周中我们了解到二分法作为分治中最常见的方法,适用于单调函数,逼近求解某点的值。
但当函数是凸形函数时,二分法就无法适用,这时就需要用到三分法。
从三分法的名字中我们可以猜到,三分法是对于需要逼近的区间做三等分:
在这里插入图片描述

我们发现lm这个点比rm要低,那么我们要找的最小点一定在[left,rm]之间。如果最低点在[rm,right]之间,就会出现在rm左右都有比他低的点,这显然是不可能的。 同理,当rm比lm低时,最低点一定在[lm,right]的区间内。
利用这个性质,我们就可以在缩小区间的同时向目标点逼近,从而得到极值。

接下来我们回到题目上,抛物线和点之间的距离可以简单的用直线公式计算:
即d = min{sqrt((X - x)2+(aX2+bX+c-y)^2)}
该公式展开后为4次,需要采用求导等方法来求极值。对于计算机编程来说是很麻烦的一件事。

进一步观察题目,我们可以发现根据带入的X值不同,d的长度恰好满足凸形函数。
而我们要求的最短距离d,正好就是这个凸形函数的极值。
那么三分法不就正好可以用来解决这道题目了么?

需要注意在解题过程中一定要想清楚如何划分区间,我们求的各个变量到底是什么含义。
另外,这道题还有一个小小的trick,在解决的时候请一定要小心。

Close

输入

第1行:5个整数a,b,c,x,y。前三个数构成抛物线的参数,后两个数x,y表示P点坐标。-200≤a,b,c,x,y≤200

输出

第1行:1个实数d,保留3位小数(四舍五入)

Sample Input

2 8 2 -2 6
Sample Output

2.437
参考笔记:https://blog.csdn.net/chenxiaoran666/article/details/79937474
https://blog.csdn.net/u012469987/article/details/50897291

#include <cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 0x3f3f3f3f;
const int N=1e6+10;
double a,b,c,x,y;
double dis(double x1){
    return sqrt(pow(x1-x,2.0)+pow(y-(a*x1*x1+b*x1+c),2.0));
}
int main(){
//    #ifndef ONLINE_JUDGE
//    freopen("in.txt","r",stdin);
//    #endif // ONLINE_JUDGE
    scanf("%lf%lf%lf%lf%lf",&a,&b,&c,&x,&y);
    double lb=-200.0-1,ub=200.0+1;
    double minv=maxn;
    for(int i=0;i<100;i++){
        double lmid=(lb+ub)/2;
        double rmid=(lmid+ub)/2;
        if(dis(lmid)<dis(rmid))
            ub=rmid;
        else
            lb=lmid;
    }
//    printf("%d %d\n",lb,ub);
    printf("%.3f\n",dis(ub));
}

对于HDU2899这一道题目来说,也算是一道入门三分的题目
Now, here is a fuction:
F(x) = 6 * x7+8*x6+7x3+5*x2-yx (0 <= x <=100)
Can you find the minimum value when x is between 0 and 100.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)
Output
Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.
Sample Input
2
100
200
Sample Output
-74.4291
-178.8534
题意:
给一函数,该函数在任意Y>0的情况下x在[0,100]内有极小值,求之。
在这里插入图片描述
思路一样,下面是AC的代码

#include <cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 0x3f3f3f3f;
const int N=1e6+10;
double y;
double dis(double x){
    return 6*pow(x,7.0)+8*pow(x,6.0)+7*pow(x,3.0)+5*pow(x,2.0)-y*x;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lf",&y);
        double lb=0,ub=100;
        for(int i=0;i<100;i++){
             double lmid = lb + (ub-lb)/3,rmid = ub - (ub-lb)/3;
            if(dis(lmid)<dis(rmid))
                 ub=rmid;
            else
                lb=lmid;
        }
        printf("%.4f\n",dis(lb));
    }
}

当然对于HDU2899这一道题目不知道图像的话可以运用模拟退火来处理
参考blog:https://blog.csdn.net/niiick/article/details/82708665


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
double INF=1000000000;
int n;
double y;
double F(double x){
    return 6*pow(x,7.0)+8*pow(x,6.0)+7*pow(x,3.0)+5*pow(x,2.0)-y*x;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
   int t;
   scanf("%d",&t);
   while(t--){
    scanf("%lf",&y);
    double x=100.0;
    double dx[2]={-1.0,1.0};
    double t=100.0;
    while(t>1e-8){
            double nx=-1.0;
      while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
      double res=F(x)-F(nx);
      if(res>=0) x=nx;
      else if(exp(res/t)>(double)rand()/(double)RAND_MAX) x=nx;
        t*=0.999;//这里如果是0.99,那么精度就不够,会WA,开成0.9999会T
    }
    printf("%.4f\n",F(x));
   }
}

上面套用的算是标准的模拟退火的板子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值