• 对于求解单峰函数最值问题的探讨


    现在已知一个单峰函数(f),求它在某个区间内的最值
    可以做到(O(nlog_3 n))或者(O(n log_2 n))(假设求该函数的一个点值是(O(1))的)

    三分法

    最常规的做法。
    每次取区间的三等分点(lmid)(rmid),比较(f(lmid))(f(rmid))的大小来缩小区间。

    • (f(lmid)>f(rmid)),最值一定在(rmid)左侧,令(r=rmid)
    • (f(lmid)<f(rmid)),最值一定在(lmid)右侧,令(l=lmid)

    注意,当函数在某个区间内为常函数时,并不能正确地得到该函数在区间内的最值。

    求导+二分

    对于单峰函数(f),显然它的一侧的是单调增的,另一侧是单调减的。
    对该函数求导,那么单调增一侧的导数(f')大于(0),单调减一侧的导数(f')小于(0),最值处的导数为(0)
    那么就可以利用二分法来确定导函数的零点。
    如果函数(f)是个常规的函数,如(n)次函数,可以直接利用公式求导。如果是个抽象函数的话,我们不妨利用导数的定义来求出该点的导数。

    [f'(x)=lim_{Delta x o 0}frac {f(x+Delta x)-f(x)} {Delta x} ]

    选择在精度允许内尽可能小的(Delta x)就可以算出(f'(x))了。
    假设求出该函数的导数的复杂度为(O(1)),那么总的复杂度是(O(n log_2 n))的。

    [模板] 三分法

    题目链接
    三分或者求导均可。
    三分代码:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int N = 20;
    const double eps = 1e-8;
    
    double a[N], l, r;
    int n;
    
    double f(double x) {
    	double ans = 0;
    	for(int i = 1; i <= n + 1; ++i) ans = 1.0 * ans * x + a[i];
    	return ans;
    }
    
    bool check(double x, double y) {
    	return f(x) < f(y);
    }
    
    int main() {
    	scanf("%d%lf%lf", &n, &l, &r);
    	for(int i = 1; i <= n + 1; ++i) scanf("%lf", &a[i]);
    	while(l + eps < r) {
    		double len = (r - l) / 3.0;
    		double lmid = l + len, rmid = r - len;
    		if(check(lmid, rmid)) l = lmid; 
    		else r = rmid;
    	}
    	printf("%.5lf
    ", l);
    }
    

    求导代码

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int N = 20;
    const double eps = 1e-8;
    
    double a[N], l, r;
    int n;
    
    double f(double x) {
    	double ans = 0;
    	for(int i = n + 1; i; --i) ans = 1.0 * ans * x + a[i];
    	return ans;
    }
    
    double check(double x) {
    	return (f(x + eps) - f(x)) / eps;
    }
    
    int main() {
    	scanf("%d%lf%lf", &n, &l, &r);
    	for(int i = n + 1; i; --i) scanf("%lf", &a[i]);
    	while(l + eps < r) {
    		double mid = (l + r) / 2.0;
    		if(check(mid) >= 0) l = mid;
    		else r = mid;
    	}
    	printf("%.5lf
    ", l);
    }
    

    BZOJ1229: [USACO2008 Nov]toy 玩具

  • 相关阅读:
    sqlite学习笔记9:C语言中使用sqlite之插入数据
    基于对话框的应用程序,点击button打开一个网页
    数组溢界地址的正确使用: 即 int a[6] 中的 a[-1] 和 a[6] 正确使用
    BeagleBone硬件概览Ethernet端口板载LEDc重置按钮等介绍
    ARP缓存记录种类动态条目和静态条目
    ArduinoYun的电源插座
    Xamarin开发Anroid应用介绍
    学习NGUI前的准备NGUI的相关信息
    Xamarin Android开发实战(上册)大学霸内部资料
    NGUI全面实践教程(大学霸内部资料)
  • 原文地址:https://www.cnblogs.com/henry-1202/p/11858945.html
Copyright © 2020-2023  润新知