solve函数程序详解(NOIP2004 提高组)

博客详细解析了一道NOIP2004提高组竞赛中的solve函数程序,涉及递归调用和循环嵌套。通过逐步模拟程序执行过程,展示了递归如何通过栈来实现并最终得到结果。文章鼓励读者自行计算得出程序的输出答案328。

此题为笔试题的读程序题。

题目程序代码如下:

#include<iostream>
using namespace std;
int number,ndata,data[100],sum;
void solve(int s,int sign,int n){
	int i;
	for(i=s;i<ndata;i++){
		sum+=sign*(number/n/data[i]);
		solve(i+1,-sign,n*data[i]);
	}
}
int main(){
	int i;
	cin>>number>>ndata;
	sum=0;
	for(i=0;i<ndata;i++) cin>>data[i];
	solve(0,1,1);
	cout<<sum<<endl;
	return 0;
} 

输入:1000 3 5 13 11

输出:

分析:此题是典型的for循环内插入递归调用,其实也可以转换成循环嵌套。在求解此题之前可以先缩小一下规模,寻找程序运行的方式。只要找到这个子问题的方式,那么这个题也就引刃而解了。

我们不如先把规模缩小。

​
#include<iostream>
using namespace std;
int number,ndata,data[100],sum;
void solve(int s,int sign,int n){
	int i;
	for(i=s;i<ndata;i++){
		sum+=sign*(number/n);
		cout<<"1."<<sum<<endl;//1代表调用递归时输出的结果
		solve(i+1,-sign,n*data[i]);
		cout<<"2."<<sum<<endl;//2表示调用递归结束后返回输出的结果
	}
}
int main(){
	int i;
	cin>>number>>ndata;
	sum=0;
	for(i=0;i<ndata;i++) cin>>data[i];
	solve(0,1,1);
      cout<<endl;
      cout<<sum<<endl;
	return 0;
}

运行此程序的结果为:

1000 3 5 13 11
1.1000
1.800
1.815
2.815
2.815
1.615
2.615
2.615
1.1615
1.1539
2.1539
2.1539
1.2539
2.2539

2539

那么现在开始模拟这个程序的执行过程:

 

首先,s,sign和n的值从主函数中传到子函数solve中的初值为0,1,1。

那么第一次执行的值为:

solve(0,1,1);
for(i=0;i<3;i++)
    sum=0+1*(1000/1)=1000;

然后调用函数,由递归式solve(i+1,-sign,n*data[i])知,此时变为solve(1,-1,1*data[0])=solve(1,-1,1*5)=solve(1,-1,5);

那么第二次执行的值为:

solve(1,-1,5);
for(i=1;i<3;i++)
    sum=1000-1*(1000/5)=800;

继续调用函数,此时变为solve(2,1,5*data[1])=solve(2,1,5*13)=solve(2,1,65);

那么第三次执行的值为:

solve(2,1,65);
for(i=2;i<3;i++)
    sum=800+1*(1000/65)=815;

继续调用函数,此时变为solve(3,-1,65);

但是,此时i=3,不符合循环条件,所以递归结束。开始返回。

 

返回:(P.S:学过的递归的oler应该都知道,递归是通过栈来实现,所以可得之前计算所产生的值都被压栈了。现在所要做的操作也就是弹栈。)

现在开始返回,由于最后一次有效递归是solve(2,1,65)。所以把最后一次递归所产生的值815带到上一层solve(1,-1,5)中。

此时执行的值为:

solve(1,-1,5);
for(i=1;i<3;i++)
    sum=815-1*(1000/5)=615;

此时sum的值为615。

这一次返回有效(“有效”意为可以进行运算)。

继续返回,这一次返回到了递归”头“(solve(0,1,1))

此时执行的值为:

solve(0,1,1);
for(i=1;i<3;i++)
    sum=1000+615=1615;

但现在还不能出来。还要重新进行新一轮递归。但运算方法与上面的一样。

此时执行的值为:

solve(1,-1,5);
for(i=2;i<3;i++)
    sum=1615-1*(1000/13)=1539;

接下来i=3,不符合条件,再一次返回。

这次返回到开头(solve(0,1,1))

此时执行的值为:

solve(0,1,1);
for(i=2;i<3;i++)
    sum=1000+1539=2539;

接下来i=3,不符合条件,再一次返回。可是这一次的位置已经是在开头,没有上层在继续返回,所以整个递归函数段结束。

 

然后就是输出2539了!

 

当然,原程序的运行原理也就是这样了(同理可得),至于答案是怎么算出来的,请读者自己去算一下。(不要怪我没说题目输出是328)

<think>好的,用户想了解MATLAB中的solve函数C++中有没有对应的方法。首先,我需要回忆一下solve函数的功能。solve主要用于求解方程和方程的符号解,属于符号计算范畴,通常涉及到符号表达式和变量。 接下来,我得想想C++中是否有直接对应的库或函数C++标准库主要处理数值计算,没有内置的符号计算功能。所以可能需要依赖第三方库。比如,可能有人用Eigen来进行数值计算,但Eigen主要是矩阵运算,不是符号求解。 然后,用户可能需要的是数值解法,比如非线性方程求解,这时候C++中可以使用数值方法,如牛顿迭代法,或者使用库如GSL(GNU Scientific Library),它提供了非线性方程求解的功能。另外,像Ceres Solver这样的优化库也可以解决最小二乘问题,可能间接用于求解方程。 另外,符号计算方面,C++有没有类似MATLAB的Symbolic Math Toolbox呢?可能有一些开源库,比如SymEngine或者GiNaC,这些库可以进行符号运算,包括解方程。例如,GiNaC允许用户定义符号变量并操作表达式,可能可以实现类似solve的功能。 不过用户可能需要具体例子来说明。比如在MATLAB中解方程x^2 - 4 = 0,用solve会得到x=2和x=-2。在C++中,如果使用数值方法,可以用GSL的根查找函数,或者用牛顿法自己实现。符号计算的话,用GiNaC可能需要构造方程并调用相应的求解函数,但具体实现可能比较复杂。 还需要考虑用户的使用场景。如果用户需要符号解,那么C++中的符号库可能比较合适,但学习曲线较陡。如果用户的问题可以用数值方法解决,那么GSL或Ceres可能更高效。 另外,可能需要比较不同方法的优缺点。符号计算精确但计算量大,适合简单的方程;数值方法速度快,但依赖于初始值,可能找到局部解。 总结下来,回答应该包括:指出MATLAB的solve属于符号计算,C++没有直接对应,但可以通过数值方法库(如GSL、Ceres)或符号计算库(如GiNaC、SymEngine)实现类似功能,并给出简单的例子说明两种方法的应用。</think>在 MATLAB 中,`solve` 函数用于求解符号方程或方程的解析解(符号解),属于符号计算范畴。而 C++ 标准库本身没有直接的符号计算功能,但可以通过以下两种方式实现类似功能: --- ### **1. 数值解法(更常见)** 若目标是求方程的数值解(近似解),C++ 中可使用数值计算库。常用方法包括: #### **示例场景:求解非线性方程 \( x^2 - 4 = 0 \)** - **MATLAB 代码**: ```matlab syms x; sol = solve(x^2 - 4 == 0, x); % 返回符号解 x = 2, -2 ``` - **C++ 实现(使用数值库)**: **a. 使用 GSL (GNU Scientific Library)** ```cpp #include <gsl/gsl_roots.h> #include <iostream> double f(double x, void* params) { return x*x - 4; // 定义方程 f(x) = x^2 -4 } int main() { gsl_function F; F.function = &f; F.params = nullptr; // 初始化求解器(使用二分法) gsl_root_fsolver* solver = gsl_root_fsolver_alloc(gsl_root_fsolver_brent); double x_low = 0, x_high = 3; // 初始区间 [0, 3] gsl_root_fsolver_set(solver, &F, x_low, x_high); int status; int iter = 0, max_iter = 100; do { iter++; status = gsl_root_fsolver_iterate(solver); double root = gsl_root_fsolver_root(solver); x_low = gsl_root_fsolver_x_lower(solver); x_high = gsl_root_fsolver_x_upper(solver); status = gsl_root_test_interval(x_low, x_high, 0, 1e-6); } while (status == GSL_CONTINUE && iter < max_iter); double root = gsl_root_fsolver_root(solver); std::cout << "Root: " << root << std::endl; // 输出近似解 2.0 gsl_root_fsolver_free(solver); return 0; } ``` **b. 使用 Ceres Solver(优化库)** ```cpp #include <ceres/ceres.h> #include <iostream> struct CostFunctor { template <typename T> bool operator()(const T* const x, T* residual) const { residual[0] = x[0] * x[0] - T(4); // 残差 = x^2 -4 return true; } }; int main() { double x = 1.0; // 初始猜测值 ceres::Problem problem; problem.AddResidualBlock( new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor), nullptr, &x); ceres::Solver::Options options; options.minimizer_progress_to_stdout = true; ceres::Solver::Summary summary; ceres::Solve(options, &problem, &summary); std::cout << "Solution: x = " << x << std::endl; // 输出近似解 2.0 return 0; } ``` --- ### **2. 符号解法(需要第三方库)** 若需解析解,可使用符号计算库,如 **SymEngine** 或 **GiNaC**。以下以 SymEngine 为例: #### **示例场景:求解 \( x^2 - 4 = 0 \)** - **C++ 代码(使用 SymEngine)**: ```cpp #include <symengine/solve.h> #include <symengine/symbol.h> #include <symengine/real_double.h> #include <iostream> using namespace SymEngine; int main() { SymbolPtr x = symbol("x"); Expression eq = pow_ex(expression(x), 2) - 4; // 构造方程 x^2 -4 = 0 set_basic solutions = solve(eq, x); // 解方程 for (auto& sol : solutions) { std::cout << "解: " << *sol << std::endl; // 输出 x = 2, x = -2 } return 0; } ``` -- ### **总结** | 方法 | 特点 | 适用场景 | |--|----------------------------------------------------------------------|------------------------------| | **数值解法** | 速度快、依赖初始猜测、只能得到近似解 | 工程计算、实时求解 | | **符号解法** | 得到精确解析解、计算复杂方程时可能受限 | 理论推导、简单方程的精确解 | 根据需求选择合适的工具,数值解法更常见于实际 C++ 项目,而符号解法需要集成第三方库。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值