1、二分法求函数根的原理为:如果连续函数f(x)在区间[a,b]的两个端点取值异号,即f(a)f(b)<0,则它在这个区间内至少存在1个根r,即f®=0。
二分法的步骤为:
检查区间长度,如果小于给定阈值,则停止,输出区间中点(a+b)/2;否则
如果f(a)f(b)<0,则计算中点的值f((a+b)/2);
如果f((a+b)/2)正好为0,则(a+b)/2就是要求的根;否则
如果f((a+b)/2)与f(a)同号,则说明根在区间[(a+b)/2,b],令a=(a+b)/2,重复循环;
如果f((a+b)/2)与f(b)同号,则说明根在区间[a,(a+b)/2],令b=(a+b)/2,重复循环。
本题目要求编写程序,计算给定3阶多项式在给定区间[a,b]内的根。
输入:输入在第1行中顺序给出多项式的4个系数a3,a2,a1,a0 ,在第2行中顺序给出区间端点a和b。题目保证多项式在给定区间内存在唯一单根。
输入样例:3 -1 -3 1
-0.5 0.5
输出:在一行中输出该多项式在该区间内的根,精确到小数点后2位。
输出样例:0.33
优化目标:本题用递归,还不是最简单的方法,具体见优化代码。
解题过程:我在读题的时候,看到了解题步骤中的最后两步“重复循环”,脑子里立马想到了递归,用递归也写出来了。在PTA里面提交的时候,结果显示部分正确,错误的一部分是没有考虑到阈值,也就是当区间长度小于一个阈值时(我的代码中,阈值是0.000001),函数值已经非常接近0了,此时只需取区间的中点即可。但当时,我没有想到这个问题,想了半天也没有解决,所以最后去网上看了看别人是怎么写的,看了过后,才发现,通过递归还不是本题最简单的方法。
我的代码:
#include <stdio.h>
#define ACCURACY 0.000001
float a3, a2, a1, a0;
float result_start, result_end, result_middle;
/*
*函数的计算
*@start: 区间起点
*@end:区间终点
*@middle:区间中点
*/
void calculat(float start, float end, float middle){
result_start = a3*start*start*start+a2*start*start+a1*start+a0;
result_end = a3*end*end*end+a2*end*end+a1*end+a0;
result_middle = a3*middle*middle*middle+a2*middle*middle+a1*middle+a0;
}
/*
*查找根
*@start: 区间起点
*@end:区间终点
*@middle:区间中点
*/
float findRoot(float start, float end, float middle){
if((end - start) >= ACCURACY){//当区间小于阈值时,直接取区间中点
calculat(start, end, middle);//计算函数值
if(result_start == 0){
printf("%.2f\n", start);//根为区间起点
return 0;
}else if(result_end == 0){
printf("%.2f\n", end);//根为区间终点
return 0;
}else{
if(result_start * result_end < 0){
if(result_middle == 0){
printf("%.2f\n", middle);
return 0;
}else{
if(result_middle * result_start >0){
//递归(middle, end)右半部分
findRoot(middle, end, (middle+end)/2);
}else{
//递归(start, middle)左半部分
findRoot(start, middle, (start+middle)/2);
}
}
}
}
}else{
printf("%.2f\n", middle);
}
}
int main(){
float start, end, middle;//根所在区间两端的变量以及区间中点
scanf("%f%f%f%f", &a3, &a2, &a1, &a0);
scanf("%f%f", &start, &end);
middle = (start + end) / 2;
findRoot(start, end, middle);
return 0;
}
优化代码:这个代码通过while循环来替代递归,也就是每一次当起点(start)与中点(middle)值同号时,则将起点(start)改为中点(middle),即实现的了右半部分的递归。当中点(middle)与终点(end)同号时,将终点(end)改为中点(middle),即实现了左半部分的递归,而最后检测”终点减去起点“是否满足阈值,满足则继续循环。最后打印结果。
#include <stdio.h>
#include <math.h>
#define ACCURACY 0.0001
int main()
{
double a3, a2, a1, a0;
double a, b, mid;
scanf("%lf%lf%lf%lf", &a3, &a2, &a1, &a0);
scanf("%lf%lf", &a, &b);
/* 若区间长度小于给定阈值,直接输出区间中点,不进入while循环 */
mid = (a + b) / 2;
while (fabs(a - b) >= ACCURACY)
{
/* 区间中点恰好是根 */
if ((a3 * pow(mid, 3) + a2 * pow(mid, 2) + a1 * mid + a0) == 0)
{
break;
}
/* 根在前半区间 */
if ((a3 * pow(a, 3) + a2 * pow(a, 2) + a1 * a + a0) * (a3 * pow(mid, 3) + a2 * pow(mid, 2) + a1 * mid + a0) < 0)
{
b = mid;
}
else // 根在后半区间
{
a = mid;
}
mid = (a + b) / 2;
}
printf("%.2f\n", mid);
return 0;
}
2、乌龟与兔子进行赛跑,跑场是一个矩型跑道,跑道边可以随地进行休息。乌龟每分钟可以前进3米,兔子每分钟前进9米;兔子嫌乌龟跑得慢,觉得肯定能跑赢乌龟,于是,每跑10分钟回头看一下乌龟,若发现自己超过乌龟,就在路边休息,每次休息30分钟,否则继续跑10分钟;而乌龟非常努力,一直跑,不休息。假定乌龟与兔子在同一起点同一时刻开始起跑,请问T分钟后乌龟和兔子谁跑得快?
输入:输入在一行中给出比赛时间T(分钟)。
**输出:**在一行中输出比赛的结果:乌龟赢输出@@,兔子赢输出_,平局则输出--;后跟1空格,再输出胜利者跑完的距离。
优化目标:看能否把代码写简洁一点。
思路:通过一个while循环来判断,条件为大于10分钟,因为主要考虑兔子每10便要抬头看情况,是睡还是继续跑。在while循环里,一进循环就让各自的路程加上10分钟所跑,然后做判断,当兔子的路程大于乌龟的路程,则兔子要睡觉,但要考虑两种情况,一是现在的时间还大于40分钟(while进来就各自跑10分钟,然后兔子睡30分钟),此时只需乌龟的路程加上30分钟跑的,并且时间减去40分钟。二是,当前时间小于40分钟,此时乌龟的路程加上剩下时间跑的,并且时间置为0,while循环结束。最后如果时间大于0小于10,还要根据情况加上这一部分时间的路程。
代码如下:
#include <stdio.h>
int main(){
int time;
int r_distance =0, t_distance=0;//兔子和乌龟所跑的距离
scanf("%d", &time);
while(time > 10){
r_distance += 10*9;
t_distance += 3*10;
if(r_distance > t_distance && time>40){
t_distance += 3*30;
time -= 40;
}else if(r_distance > t_distance && time < 40){//睡觉中赢
t_distance += 3*(time-10);
time = 0;
}else{
time -= 10;
}
}
if(time != 0){
if(r_distance>t_distance){
t_distance += 3*time;
}else{
r_distance += 9*time;
t_distance += 3*time;
}
}
if(r_distance > t_distance){
printf("^_^ %d", r_distance);
}else if(r_distance < t_distance){
printf("@_@ %d", t_distance);
}else{
printf("-_- %d", r_distance);
}
return 0;
}
3、今天学写了动态数组及对数组的基本操作。但还没写完,就不放在今天的内容中了。明天给出。
总结:今天最深刻的就是第一题了,递归很好,但当左右两边都同时需要递归时,递归才是最好的。而今天的第一题只有一半需要递归,所以这里用递归就有点不恰当了。此外,在PTA上做题的时候,如果遇到逻辑比较复杂的题,在自己写出来后,也尽量看看别人写的好的代码,有时候自己的逻辑还是稍显复杂了,多学学别人写的。