普及-每日一題洛谷P1024
有形如:\(a x^3 + b x^2 + c x + d = 0\) 這樣的一個一元三次方程。給出該方程中各項的係數(\(a,b,c,d\) 均為實數),並約定該方程存在三個不同實根(根的範圍在 \(-100\) 至 \(100\) 之間),且根與根之差的絕對值 \(\ge 1\)。要求由小到大依次在同一行輸出這三個實根(根與根之間留有空格),並精確到小數點後 \(2\) 位。
提示:記方程 \(f(x) = 0\),若存在 \(2\) 個數 \(x_1\) 和 \(x_2\),且 \(x_1 < x_2\),\(f(x_1) \times f(x_2) < 0\),則在 \((x_1, x_2)\) 之間一定有一個根。
輸入
一行,\(4\) 個實數 \(a, b, c, d\)。
輸出
一行,\(3\) 個實根,從小到大輸出,並精確到小數點後 \(2\) 位。
樣例輸入
1 -5 -4 20
樣例輸出
-2.00 2.00 5.00
經典的二分求值問題,這道題題目限制了根的範圍:根與根之差的絕對值 \(\ge 1\) ,根的範圍在 \(-100\) 至 \(100\) 之間
於是,我們的大致流程就是:
-
透過\(f(x_1) \times f(x_2) < 0\),尋找到一個區間\((x_1, x_2)\)使得其中必存在一個根
-
由於根與根之差的絕對值 \(\ge 1\) ,所以尋找區間時,可以以 \(1\) 作為一個跨度
-
再使用二分法,在含根區間內找到一個近似根
-
題目要求:精確到小數點後 \(2\) 位,這就存在兩種找到根的途徑:
-
二分的
mid
代入方程中,直接可解出 0 -
透過左邊界
l
和右邊界r
向根無限逼近,存在一個精度限制透過題目可知:精度需要在小數點後兩位,所以在逼近根的時候,只需要控制左邊界和右邊界的差小於等於\(0.001\),
這時不妨舉例有:\(l=1.005,r=1.006,root=1.00\) 任意選取
l或r
作為近似根,保留兩位小數後,與根的大小几乎相同,可以認為找到了一個根
-
程式碼首先實現\(f(x)\)的操作:
double fx(double x) {
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
構建fx
函式,方便之後呼叫求值
然後實現在區間內尋找根的函式find
:
double find(double l, double r) {
while (r-l>0.001)//控制近似根的誤差小於等於0.001
{
double mid = (l + r) / 2;
if (fx(l) * fx(mid) <= 0)
r = mid;
else
l = mid;
}
return l;//返回l或r都可以
}
最後執行在\([-100,100]\)之間尋找含根區間:
for (int i = -100; i <= 100; i++) {
double l = i, r = i + 1;
double x1 = fx(l), x2 = fx(r);
if (x1 == 0) {//判斷端點值是否恰好為根
printf("%.2lf ", l);
cnt++;
continue;
}//只用判斷左端點
if (x1 * x2 < 0) {
printf("%.2lf ", find(x1,x2));
cnt++;//記錄根的個數
}
if (cnt == 3) return 0;//根全部解完後直接退出
}
完整AC程式碼:
double a, b, c, d;
double fx(double x) {
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
double find(double l, double r) {
while (r-l>0.001)
{
double mid = (l + r) / 2;
if (fx(l) * fx(mid) < 0)
r = mid;
else
l = mid;
}
return l;
}
int main()
{
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
int cnt = 0;
for (int i = -100; i <= 100; i++) {
double l = i, r = i + 1;
double x1 = fx(l), x2 = fx(r);
if (x1 == 0) {
printf("%.2lf ", l);
cnt++;
continue;
}
if (x1 * x2 <= 0) {
printf("%.2lf ", find(x1,x2));
cnt++;
}
if (cnt == 3) return 0;
}
return 0;
}