《算法问题实战策略》-chaper13-数值分析
这一章节主要介绍我们在进行数值分析常用的二分、三分和一个近似求解区间积分的辛普森法。
首先介绍二分。
其实二分的思想很好理解并且笔者在之前的一些文章中也有所渗透,对于二次函数甚至单元高次函数的零点求解、线段树还有《algorithm puzzle》当中的“切割钢条”问题,都是基于二分思想。
下面我们通过具体的问题来应用二分这种数值分析的策略。
Ex1:按揭贷款
以P%的年利率借贷N元后,在M个月内,以每月还C元的方式还贷。贷款期限内,按照如下形式计算贷款余额。
(1) 贷款余额从余额N元开始。
(2) 美国一个月,贷款余额会增加一个月的利息,月利率为(P/12)%。
(3) 增加利息后,从贷款余额中扣除当月的还款项。
分析:我们从较为抽象化的角度来建立一个数学模型,这道问题M,P,N,C等输入数据相当于是自变量,而还贷过程相当于是个函数机制,M月后的借贷余额便是因变量。
对于函数的这三要素,我们都是知道的,那么我们可以将问题转化成在满足因变量≤0的情况下,求解C的最小值。
如果我们想尝试利用数学方法,会发现我们虽然了解函数机制,但是我们难以列出其表达式,因此这里我们基于自变量C的解区间,进行二分搜索,而这个过程恰恰基于函数机制和因变量(函数余额)的范围限制。
简单的参考代码如下:
#include<cstdio> using namespace std; double balance(double amount , int duration , double rates , double monthlypayment)//求解每月还贷monthlypayment元,duration个月后的贷款余额。 { double balance = amount;//贷款余额初始化 for(int i = ;i < duration;i++) { balance *= (1.0 + (rates/12.0)/100.0);//这里涉及简单的还贷机制,我们将其理解为每月底涨息后还贷 balance -= monthlypayment; } return balance; } double payment(double amount , int duration , double rates) { double l = ;//每月还贷可行解的区间,基于这道问题的特殊情景(区间右端点一定可行,这与这个函数最后return的变量呼应),解区间分布情况是(,] double r = amount*(1.0 + (rates/12.0)/100.0); double mid; for(int i = ;i < ;i++) { mid = (r + l)/2.0; if(balance(amount , duration , rates , mid) <= ) r = mid; else l = mid; } return r; } int main() { double amount , rates; int duration; printf("Input amount,rates and duration:"); scanf("%lf %lf %d",&amount,&rates,&duration); printf("the lowest monthlypayment: %llf",payment(amount,duration,rates)); }
下面我们开始介绍三分。
其实所谓三分,如果百度一下,会发现在百度百科里它是一种“哲学形态”出现的,并且被称为典型的中国思维,即在解决问题的时候基于西方所谓“二分”的思维,将正反对立双方进行统一,形成事物的“第三面”。
但是我们这里并不从哲学的角度去看待三分,而是从数值分析的角度去看待三分,即将其看成一种筛选解的搜索方式。
对于一个函数f(x),考察其在[lo,hi]上的性质。
零点:这个我们都很熟悉,利用二分法可以快速求解,但是为什么要在这里介绍呢?是为了将其与三分进行区别和联系。
极值点:
为了讨论的方便和算法的简便,我们统一一下讨论的函数,它在区间[lo,hi]上先严格递增后严格递减,存在一个极大值点。
想一想,如果想用这种基于解区间进行搜索的办法,利用二分能否能够实现呢?不能。因为对于零点,我们所基于的解空间的两端仿佛就是走了两个极端,一个大于0一个小于0,这导致零点必然会落在这之间,并且二分区间之后依然能够容易得得到更小的解区间,而对于极值的情况,显然解区间的两个端点要么都小于极值点的,因此这样你二分是无法选择下一个更下的解区间,这就使得搜索过程变得没了意义。
那应该怎么处理呢?这就很自然的引出了今天的主角——三分法。我们将区间[lo,hi]三等分(三等分点怎么求就不必我多说了),无非会出现如下的两种情况:
(1)左三等分点对应的函数值较大,那么我们可以很肯定的说,三等分区间之中最右边的区间一定不会有极值,因为假设最右边的区间上还有极值点,按照我们先前的定义,极值点的左侧是严格递增的,这与事实相悖。
(2)同理,如果右三等分点对应的函数值较大,我们能够排除三等分区间的最左侧的区间。
而类似于二分搜索法,对于在实数区间上的三分搜索,我们默认进行100次三分之后终止,得到近似解。
简单的函数代码如下。
double f(double x);//求解函数值f(x) double ternary(double lo , double hi) { double a = (*lo + hi)/;//左三等分点 double b = (lo + *hi)/;//右三等分点 for(int i = ;i < ;i++)//三分100次终止 { if(f(a) < f(b)) lo = a; else hi = b; } return (lo + hi)/; }
辛普森法:
所谓辛普森法,即是在求解函数f(x)在[a,b]区间上的积分是,将x = a、b、(a + b)/2三点视作抛物线上的三个点,这样我们通过简单的定积分运算,可以得到一个公式,即:
但是,上面提到的“将三点视为抛物线上的三个点”这种近似处理显然是要付出相应的代价的,这里在微积分的层面就要用到极限的思维方法,但是在这里我们从计算机编程的角度来看,我们基于二分来设计一个递归过程来“偿还”这种代价。
假设我们求得了[a,b]上的积分,我们分别二分区间得到[a,(a+b)/2]、[(a+b)/2,b]并用相同的办法求出这两个区间上的积分值,限制二者的和与先前求得的积分误差在1e-10以内,则表明认为符合了我们上文提到的“近似”处理,否自,我们继续二分区间,形成一个递归过程,知道满足误差的限定为止。
我们通过一个具体的题目来实现这个算法流程。(Problem source : hdu 1724)
给出一个椭圆方程,的两个参数a、b和一个区间[c,d]的左右端点,请求解直线x = c,x=d和椭圆围成的面积。
简单的参考代码如下:
#include <iostream>
#include <math.h>
#include<cstdio>
using namespace std; const double esp = 1e-;
double a,b; double f(double x)//被积函数
{
return b * sqrt(1.0-(x*x)/(a*a));
} double simpson(double l,double r)
{
return (f(l)+*f((l+r)/2.0)+f(r))/6.0*(r-l);
} double integral(double l,double r)
{
double mid = (l+r)/2.0;
double res = simpson(l,r);
if (fabs(res-simpson(l,mid)-simpson(mid,r)) < esp)
return res;
else
return integral(l,mid) + integral(mid,r);
}
int main()
{
int T;
double l,r;
cin >> T;
while (T--)
{
cin >> a >> b >> l >> r;
printf("%.3lf\n",*integral(l,r));
}
return ;
}
《算法问题实战策略》-chaper13-数值分析的更多相关文章
- 算法问题实战策略 PICNIC
下面是另一道搜索题目的解答过程题目是<算法问题实战策略>中的一题oj地址是韩国网站 连接比较慢 https://algospot.com/judge/problem/read/PICNIC ...
- 《算法问题实战策略》-chaper7-穷举法
关于这一章节<算法实战策略>有一段概述问题,我认为对于编程人员来说非常有价值,故在这里进行如下的摘抄: 构想算法是很艰难的工作.相比大家都经历过,面对复杂的要求只是傻乎乎地盯着显示器,或者 ...
- 《算法问题实战策略》-chaper32-网络流
基本的网络流模型: 在图论这一块初步的应用领域中,两个最常见的关注点,其一时图中的路径长度,也就是我们常说的的最短路径问题,另一个则是所谓的“流问题”. 流问题的基本概念: 首先给出一张图. 其实所谓 ...
- 《算法问题实战策略》——chaper9——动态规划法技巧
Q1: 数字游戏: 两个人(A.B)用n个整数排成的一排棋盘玩游戏,游戏从A开始,每个人有如下操作: (1) 拿走棋盘最右侧或者最左侧的棋子,被拿走的数字从棋盘中抹掉. (2) 棋盘中还剩 ...
- 《算法问题实战策略》-chaper8-动态规划法
Q1:偶尔在电视上看到一些被称为“神童”的孩子们背诵小数点以后几万位的圆周率.背诵这么长的数字,可利用分割数字的方法.我们用这种方法将数字按照位数不等的大小分割后再背诵. 分割形式如下: 所有数字都相 ...
- 《算法问题实战策略》-chaper21-树的实现和遍历
这一章节开始介绍一个数据结构中的一个基本概念——树. 我们从数据结构的解读来解释树结构的重要性,现实世界的数据除了最基本的线性结构(我们常用队列.数组和链表等结构表征),还有一个重要的特性——层级结构 ...
- 算法问题实战策略 QUADTREE
地址 https://algospot.com/judge/problem/read/QUADTREE 将压缩字符串还原后翻转再次压缩的朴素做法 在数据量庞大的情况下是不可取的 所以需要在压缩的情况下 ...
- 算法问题实战策略 DICTIONARY
地址 https://algospot.com/judge/problem/read/DICTIONARY 解法 构造一个26字母的有向图 判断无回路后 就可以输出判断出来的字符序了 比较各个字母的先 ...
- 算法问题实战策略 MEETINGROOM 附一份tarjan模板
地址 https://algospot.com/judge/problem/read/MEETINGROOM 解答 2-sat 代码样例过了 没有ac. 我又没有正确代码对拍..... 已确认是输出 ...
随机推荐
- C#解leetcode 16. 3Sum Closest
Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...
- MySQL存储过程详解 mysql 存储过程(二)
mysql存储过程详解 1. 存储过程简介 我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL ...
- 一位ACM过来人的心得
刻苦的训练我打算最后稍微提一下.主要说后者:什么是有效地训练? 我想说下我的理解. 很多ACMer入门的时候,都被告知:要多做题,做个500多道就变牛了.其实,这既不是充分条件.也不会是必要条件. 我 ...
- Ajax+Node分页
思路: ajax分页:1.服务器server.js,写布局;2.写接口文档(不管客户端,只写服务器端接口)3.写客户端,绑定数据,分页,优化点击过了,就不再请求:4.给每个li绑定点击事件,跳转详情页 ...
- java编程思想-泛型思维导图
- mybatis 一对一关联
首先建表: CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name VARCHAR(20) ); CREATE TABLE ...
- MPICH2在两台Ubuntu上安装(用mpd做进程管理)
本文在经过大量的实验终于不负众望成功的在两台Ubuntu 12.04上部署MPI的一个小型集群,MPICH2所用版本为mpich2-1.4.1,下载地址:http://www.mcs.anl.gov/ ...
- python运维开发之第六天
Python面向对象 python从设计之初就已经是一门面向对象的语言,在python中创建一个类和对象很容易. 面向对象简介:类(class),类变量,object(基类),实例变量,构造函数,封装 ...
- tornado项目
tornado项目之基于领域驱动模型架构设计的京东用户管理后台 本博文将一步步揭秘京东等大型网站的领域驱动模型,致力于让读者完全掌握这种网络架构中的“高富帅”. 一.预备知识: 1.接口: pytho ...
- 针对上一篇文章中的代码,想出的重构方案(python实现)
#!/usr/bin/env python class Processor: def __init__(self, processor): self.processor = processor def ...