zoukankan      html  css  js  c++  java
  • 学习笔记:三分法(唔,好像不是唉)

    明明保存了,却奇怪的消失了,真令人迷惑,只好再写一遍。
    题目链接:P3382 【模板】三分法
    我们知道极值处导函数值为(0),那么我们把这个函数的导数求出来,二分答案即可。
    刚刚学习了导数,来看一下与这题有关的导数法则。

    [[f(x)pm g(x)]'=f'(x)pm g'(x) ]

    那我们推导到更多加减法的求导,对于一个(n)次多项式(f(x))

    [f(x)=sumlimits_{i=0}^na_ix^i ]

    显然,它的导数是:

    [f'(x)=sumlimits_{i=0}^{n-1}(i+1)a_{i+1}x^i ]

    这个直接模拟就好了。

    关于多项式的求值

    对于高次项,容易想到对自变量(x)快速幂,不过这样是(mathcal O(nlog n))的,有没有更好的方法呢?
    有!
    早在很早以前,中国数学家秦九韶就提出了秦九韶算法,我们来举个栗子吧。
    有一个多项式(g(x)):

    [g(x)=ax^3+bx^2+cx+d ]

    我们这样化简一下:

    [g(x)=x(x(xa+b)+c)+d ]

    这样就能(mathcal O(n))了。

    double f(double g,int n)//求n次多项式f(g)的值
    {
    	double x=fuc[n];
    	for(int i=1;i<=n;i++) x=g*x+fuc[n-i];
    	return x;
    }
    

    自己的想法

    在讲述秦九韶算法时,莫名发现一种奇妙算法:
    快速幂为什么慢呢?
    显然是重复处理了一些幂次,那我们直接暴算幂次即可,这样也是(mathcal O(n))的:

    double f(double g,double n)
    {
    	double x=1,ans=0;
    	for(int i=0;i<=n;i++) ans=ans+x*fuc[i],x*=g;
    	return ans;
    } 
    

    然后这道题就做完了:

    (Code):

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define read(x) scanf("%d",&x)
    #define read_d(x) scanf("%lf",&x)
    double fuc[20];
    double a[20];
    int n;
    double l,r;
    double f(double g,int n)
    {
    	double x=fuc[n];
    	for(int i=1;i<=n;i++) x=g*x+fuc[n-i];
    	return x;
    }
    int main()
    {
    	read(n),read_d(l),read_d(r);
    	for(int i=n;i>=0;i--) read_d(a[i]);
    	//求导 
    	for(int i=n;i>=1;i--) fuc[i-1]=a[i]*i;
    	double mid;
    	for(int i=1;i<=100;i++)
    	{
    		mid=(l+r)/2;
    		if(f(mid,n-1)<0) r=mid;
    		else l=mid;
    	}
    	printf("%.5lf
    ",mid);
    	return 0;
    }
    

    那么你如果对于多项式函数的求导一般式一脸懵逼,那么直接按定义做就好了:
    我们知道导数的定义为:

    [f'(x)=limlimits_{mathitDelta x ightarrow 0}dfrac{f(x+mathitDelta x)-f(x)}{mathitDelta x} ]

    我们可以把(mathitDelta x)设成很小的数如(10^{-10}),然后就行了。
    大佬是这样做的,我来搬运代码:

    (Code):

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 15;
    const double eps = 1e-10;;
    int n;
    double L, R, a[N];
    double f(double x) {
    	double c[N];
    	c[n] = a[n];
    	for (int i = n - 1; i >= 0; --i) c[i] = c[i + 1] * x + a[i];
    	return c[0];
    }
    double check(double x) {
    	double dx = eps;
    	double dy = f(x + eps) - f(x);
    	return dy / dx;
    }
    int main() {
    	cin >> n >> L >> R;
    	for (int i = 0; i <= n; ++i) cin >> a[n - i];
    	double mid; 
    	while (R - L > eps) {
    		mid = (L + R) / 2;
    		if (check(mid) > 0) L = mid;
    		else R = mid; 
    	}
    	printf("%.5lf", L);
    	return 0;
    } 
    

    关于复杂度:
    二分(100)次的话就是(mathcal O(100n))了,或者写成( mathcal O(nlog eps))
    (ps):我自己(yy)的竟然比秦九韶算法快(8;ms)

  • 相关阅读:
    C#循环页面form中控件
    鼠标放到按钮上页面样式发生变化
    access INSERT INTO 语句的语法错误
    更改水晶报表数据源
    C# byte[]与string互转
    禁用右键
    showModalDialog IE9 报错
    ListBox 循环删除当前项
    showModalDialog 刷新本页面,不重新发送信息,则无法刷新网页,Page_PreRender
    敏捷模式开发(转)
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12623204.html
Copyright © 2011-2022 走看看