★P1024 [NOIP 2001 提高组] 一元三次方程求解
题目描述
有形如:
提示:记方程
输入格式
一行,
输出格式
一行,
输入输出样例 #1
输入 #1
1 -5 -4 20
输出 #1
-2.00 2.00 5.00
说明/提示
【题目来源】
NOIP 2001 提高组第一题
题解
#include <bits/stdc++.h> using namespace std; double a, b, c, d; vector<double> roots; double f(double x) { return a*x*x*x + b*x*x + c*x + d; } // 本题有一个测试点会重复计入根,当一个端点(例如 i 或 i+1)正好满足 f(x) ≈ 0 时,代码会先直接把这个端点加入根列表;随后在同一个区间,二分法又找到了一个近似相同的根,导致重复计入,这里添加判断防止重复,在每次加入新根前,可以判断当前新根与已存在根的距离是否足够大(如大于 1e-6),如果非常接近则跳过。 bool isNewRoot(double x) { for (double r : roots) { if (fabs(r - x) < 1e-6) return false; } return true; } void search() { for (double i = -100; i < 100; i++) { double left = i, right = i + 1; // 判断端点是否为根 if (fabs(f(left)) < 1e-6 && isNewRoot(left)) { roots.push_back(left); if (roots.size() == 3) break; continue; // 跳过本次区间的二分,防止重复计入 } if (fabs(f(right)) < 1e-6 && isNewRoot(right)) { // 如果右端点是根,先尝试二分法,避免重复 if (f(left)*f(right) < 0) { // 二分求根 while (right - left > 1e-7) { double mid = left + (right - left) / 2; if (f(mid) * f(left) < 0) right = mid; else left = mid; } double root = (left + right) / 2; if (isNewRoot(root)) { roots.push_back(root); if (roots.size() == 3) break; } } else { // 如果区间内没有符号变化,则直接添加右端点 roots.push_back(right); if (roots.size() == 3) break; continue; } } // 对于一般情况,判断区间内是否有根 if (f(left) * f(right) < 0) { while (right - left > 1e-7) { double mid = left + (right - left) / 2; if (f(mid) * f(left) < 0) right = mid; else left = mid; } double root = (left + right) / 2; if (isNewRoot(root)) { roots.push_back(root); if (roots.size() == 3) break; } } } } int main() { cin >> a >> b >> c >> d; search(); sort(roots.begin(), roots.end()); for (size_t i = 0; i < roots.size(); i++) { if (i > 0) cout << " "; printf("%.2lf", roots[i]); } cout << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了