zoukankan      html  css  js  c++  java
  • 秦九韶算法 & 三分法

    前言

    今天考试出了一个题
    郭郭模拟退火骗了75分
    于是再次把咕咕了好久的模退提上日程
    如果进展顺利
    明后天应该会开爬山算法和模退的博客笔记
    今天先把今天考试的正解学习一下——三分法

    引入

    老规矩上板子题
    LuoguP3382

    题目描述

    给出一个 (N) 次函数,保证在范围 ([l,r]) 内存在一点 (x),使得 ([l,x]) 上单调增,([x,r]) 上单调减。试求出 (x) 的值。

    输入格式

    第一行一次包含一个正整数 (N) 和两个实数 (l,r),含义如题目描述所示。
    第二行包含 (N+1) 个实数,从高到低依次表示该 (N) 次函数各项的系数。

    输出格式

    输出为一行,包含一个实数,即为 (x) 的值。四舍五入保留 (5) 位小数。

    Input

    3 -0.9981 0.5
    1 -3 -3 1
    

    Output

    -0.41421
    

    秦九韶算法

    背景(废话)

    秦九韶算法是一种将一元n次多项式的求值问题转化为n个一次式的算法。
    其大大简化了计算过程,即使在现代,利用计算机解决多项式的求值问题时,秦九韶算法依然是最优的算法。
    在西方被称作霍纳算法,是以英国数学家霍纳命名的。

    计算方法

    求多项式的值:

    [f(x) = a_0 + a_1x + a_2x^2+a_3x^3+cdots+a_nx^n ]

    一眼暴力直接求值
    那还要秦九韶干啥
    本质就是提公因式

    [f(x)=a_0+x(a_1+a_2x+a_3x^2+cdots+a_nx^{n -1}) ]

    [f(x)=a_0+x(a_1+x(a_2+a_3x+cdots+a_nx^{n -2}) ]

    顺序进行到最后

    [f(x)=(cdots(a_nx+a_{n-1})x+a_{n-2})x+cdots+a_1)x+a_0 ]

    来看一个五次式

    [f(x)=x^5+x^4+x^3+x^2+x+1quad (x=5) ]

    暴力求需要10个乘法
    利用秦九韶算法显然可以只成4次
    这下就大大改善了效率
    显然的,次数越高
    算法效率优化越明显


    接下来进入正题:三分法

    三分法

    简介

    三分法一般用来求某一个单峰函数的最值。
    没了。。。
    和二分的区别就是
    二分要求区间单调
    三分要求只有一个“单峰”,即最值

    实现

    给定上下界,每次将上下界这个区间平均分成三份,取两个三等分点比较,并缩小范围。
    三分法就是单峰函数求最值
    当前我们位于([l,r])
    然后我们我们有两个三等分点(mid,mmid(mid<mmid))
    也不一定非要两个三等分点,只是举个例子
    假设我们求最大值
    我们比较(f(mid))以及(f(mmid))
    1.(f(mid)>f(mmid))
    那么可以确定的是(mmid)一定位于最值右边
    2.(f(mid)<f(mmid))
    那么可以确定的是(mid)一定位于最值左边

    Code

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    using namespace std;
    
    inline int read(){
    	int x = 0, w = 1;
    	char ch;
    	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
    	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    const double eps = 1e-8;
    double a[20];
    int n;
    
    inline double f(double x){
    	double ans = 0.0;
    	for(int i = n; i >= 0; i--)
    		ans = ans * x + a[i];
    	return ans;
    }
    
    double l, r;
    signed main(){
    	n = read();
    	cin >> l >> r;
    	for(int i = n; i >= 0; i--)
    		cin >> a[i];
    	while(fabs(l - r) >= eps){
    		double midl = l + (r - l) / 3;
    		double midr = r - (r - l) / 3;
    		if(f(midl) > f(midr))
    			r = midr;
    		else l = midl;
    	}
    	printf("%.5lf
    ", l);
    	return 0;
    }
    

    小结

    这么来看三分还是很简单的(doge
    这个板子求导+二分好像也能做
    但是咱们今天学习板子对吧
    稍等做完T4会把题目放到下面

  • 相关阅读:
    PHP 单态设计模式
    五中常见的PHP设计模式
    PHP如何定义类及其成员属性与操作
    thinkphp 中MVC思想
    1.4 算法
    1.3 迭代器
    1.2 容器-container
    1.1 STL 概述
    2.3顺序容器-deque
    2.2 顺序容器-list
  • 原文地址:https://www.cnblogs.com/rui-4825/p/13442600.html
Copyright © 2011-2022 走看看