模块化
2026-07-28 12:08:00
发布于:湖北
12阅读
0回复
0点赞
这段代码实现了一个一元二次方程求解器,能够根据判别式的不同情况,输出格式化的较大解:
全局变量声明
int T,m,a,b,c,d,k,t;
| 变量 | 含义 |
|---|---|
T |
测试用例数量 |
m |
题目中的参数(但代码中未使用) |
a,b,c |
方程 的系数 |
d |
判别式 (化简后根号内的数) |
k |
化简后的系数,即 |
t |
临时变量,用于存储最大公约数 |
gcd 函数:求最大公约数
int gcd(int a,int b){
return b ? gcd(b, a%b) : a;
}
- 三元运算符:
b ? A : B表示"如果 b 非零则 A,否则 B" - 递归实现:欧几里得算法,求
a和b的最大公约数 - 等价写法:
if (b != 0) return gcd(b, a % b); else return a;
Main() 函数:核心逻辑
步骤 1:读取系数并标准化
cin >> a >> b >> c;
if (a < 0) a = -a, b = -b, c = -c; // 细节1:分母非负
为什么这样做?
- 方程 两边同乘 -1,解不变
- 保证
a > 0,后续计算2a作为分母时为正,简化符号处理
步骤 2:计算判别式并判断无解
d = b*b - 4*a*c, k = 1; // d是delta
if (d < 0) {
cout << "NO\n";
return;
} // 无解
- 时无实数解,直接输出
NO
步骤 3:化简
for (int i = 2; i*i <= d; i++)
while (d % (i*i) == 0)
k *= i, d /= (i*i); // k*sqrt(d)
核心技巧:提取所有平方因子
| 示例 | 过程 | 结果 |
|---|---|---|
| → | ||
| → | ||
| 无平方因子 → |
步骤 4:有理数解( 是完全平方数)
if (d == 0 || d == 1) { // 有理数
t = abs(gcd(2*a, -b + k*d)); // 细节2:取绝对值
cout << (-b + k*d) / t;
if (2*a / t != 1) // 细节3:分母非1
cout << '/' << 2*a / t;
cout << '\n';
return;
}
数学原理:
- :,解为
- :(整数),解为
输出格式:
- 分子分母约分后,如果分母为 1 则只输出分子
- 否则输出
分子/分母
步骤 5:无理数解( 不是完全平方数)
// -b/2a + k*sqrt(d)/2a
t = abs(gcd(-b, 2*a)); // 细节2
if (-b/t == 0) // 细节4:不能有0+xxx
goto g;
cout << -b/t;
if (2*a/t != 1) // 细节3
cout << '/' << 2*a/t;
cout << '+';
g:
t = abs(gcd(k, 2*a)); // 细节2
if (k/t != 1) // 细节5:乘数不为1
cout << k/t << '*';
cout << "sqrt(" << d << ')';
if (2*a/t != 1) // 细节3
cout << '/' << 2*a/t;
cout << '\n';
数学原理:
代码逻辑:
- 输出 部分(如果不为 0)
- 约分:
gcd(-b, 2a) - 如果分子为 0,用
goto g跳过,避免输出0+...
- 约分:
- 输出
+连接符 - 输出 部分
- 约分:
gcd(k, 2a) - 如果系数为 1,省略
1* - 如果分母为 1,省略
/1
- 约分:
5 个"细节"详解
| 细节 | 代码位置 | 作用 |
|---|---|---|
| 细节1 | if(a<0) a=-a,b=-b,c=-c |
保证分母 2a > 0,简化符号处理 |
| 细节2 | abs(gcd(...)) |
gcd 可能返回负数,取绝对值保证约分正确 |
| 细节3 | if(2*a/t!=1) |
分母为 1 时不输出 /1,符合数学书写习惯 |
| 细节4 | if(-b/t==0) goto g |
避免输出 0+sqrt(...),直接输出 sqrt(...) |
| 细节5 | if(k/t!=1) |
系数为 1 时不输出 1*,如 sqrt(2) 而非 1*sqrt(2) |
main() 函数:输入输出框架
int main(){
freopen("uqe.in","r",stdin); // 重定向标准输入
freopen("uqe.out","w",stdout); // 重定向标准输出
for (cin >> T >> m; T; --T) // 循环 T 次
Main(); // 处理每个用例
fclose(stdin); // 关闭文件
fclose(stdout);
return 0;
}
文件重定向:
- 提交 OJ 时,程序会自动从
uqe.in读输入,向uqe.out写输出 - 本地调试时可注释掉这两行,用控制台输入输出
样例执行演示
样例:(a=1, b=-3, c=2)
d = (-3)² - 4×1×2 = 9 - 8 = 1d == 1→ 有理数解- 分子:
-b + k*d = 3 + 1×1 = 4 - 分母:
2a = 2 - 约分:
gcd(4, 2) = 2→4/2 = 2,2/2 = 1 - 输出:
2✓
样例:(a=1, b=0, c=-2)
d = 0² - 4×1×(-2) = 8- 化简:
8 = 2² × 2→k=2, d=2 d != 0,1→ 无理数解- (跳过输出)
- (系数为 1,省略)
- 输出:
sqrt(2)✓
#include<bits/stdc++.h>
using namespace std;
int T,m,a,b,c,d,k,t;
int gcd(int a,int b){//最大公因数
return b?gcd(b,a%b):a;
}
void Main(){
cin>>a>>b>>c;
if(a<0)
a=-a,b=-b,c=-c;//细节1:分母非负
d=b*b-4*a*c,k=1;//d是delta
if(d<0){
cout<<"NO\n";
return;
}//无解
for(int i=2;i*i<=d;i++)
while(d%(i*i)==0)
k*=i,d/=(i*i);//k*sqrt(d)
if(d==0||d==1){//有理数
t=abs(gcd(2*a,-b+k*d));//细节2:取绝对值
cout<<(-b+k*d)/t;
if(2*a/t!=1)//细节3:分母非1
cout<<'/'<<2*a/t;
cout<<'\n';
return;
}
//-b/2a+k*sqrt(d)/2a
t=abs(gcd(-b,2*a));//细节2
if(-b/t==0)//细节4:不能有0+xxx
goto g;
cout<<-b/t;
if(2*a/t!=1)//细节3
cout<<'/'<<2*a/t;
cout<<'+';
g:
t=abs(gcd(k,2*a));//细节2
if(k/t!=1)//细节5:乘数不为1
cout<<k/t<<'*';
cout<<"sqrt("<<d<<')';
if(2*a/t!=1)//细节3
cout<<'/'<<2*a/t;
cout<<'\n';
return;
}
int main(){
freopen("uqe.in","r",stdin);
freopen("uqe.out","w",stdout);
for(cin>>T>>m;T;--T)
Main();//函数
fclose(stdin);
fclose(stdout);
return 0;
}
全部评论 1
冷知识:gcd函数可以用内置的宏函数__gcd,作用都是求两数的最大公因数
昨天 来自 浙江
0











有帮助,赞一个