温馨提示,本题解提供多种思路的代码与解析(有一些不准确)!
目录
题目描述
输入描述
输出描述
解析
完整代码
描述
你的任务是计算a+b。这是为了acm初学者专门设计的题目。你肯定发现还有其他题目跟这道题的标题类似,这些问题也都是专门为初学者提供的。
输入两个数,回车后输出结果,然后再输入一对,回车再输出结果。。。。
输入描述
输入包含一系列的a和b对,通过空格隔开。一对a和b占一行。
输出描述
对于每次输入的每对a和b,你需要依次输出a、b的和。
用例输入 1
1 5
用例输出 1
6
来源
算法笔记 基础循环
简单方法
为了处理一系列输入的a和b对,并在每次输入后输出它们的和,我们可以使用C++中的循环结构。这个程序会一直读取输入,直到没有更多的数据为止(例如,通过按Ctrl+D或Ctrl+Z+Enter在命令行中结束输入)。以下是一个符合你描述的C++程序示例:
#include <iostream>
int main() {
int a, b;
// 使用一个无限循环来不断读取输入
while (true) {
// 尝试从标准输入读取两个整数
std::cin >> a >> b;
// 检查输入是否成功,如果不成功则退出循环
if (std::cin.fail()) {
break;
}
// 计算a和b的和
int sum = a + b;
// 输出结果到标准输出
std::cout << sum << std::endl;
}
return 0;
}
然而,在实际比赛中,通常不会使用无限循环和std::cin.fail()来检查输入结束。相反,更常见的是使用某种形式的输入结束标记,或者从文件读取数据。但在这个特定的问题中,由于题目描述并没有提供明确的输入结束标记,我们假设用户会在输入完所有数据后手动结束输入。
记忆化搜索方法
记忆化搜索(Memoization Search)是一种优化技术,通常用于优化递归搜索算法,通过记录已经计算过的结果以避免重复计算。这种方法特别适用于解决动态规划问题和一些具有重叠子问题特性的递归问题。
对于简单的A+B问题,实际上并不需要使用记忆化搜索,因为这是一个非常基础且计算量很小的操作。然而,为了展示记忆化搜索的应用,我们可以构想一个更复杂的场景,其中A和B可能是某种复杂计算的结果,而这些计算可以通过记忆化来优化。
但在这里,为了符合题目的原始要求(即输入A、B,输出A+B),我们将展示一个简化的记忆化搜索框架,尽管在这个特定问题上它并不是必需的。这个框架主要是为了展示记忆化搜索的技术,而不是真正用于优化A+B的计算。
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
// 我们有一个复杂的函数来计算A或B
int complexCalculation(int x) {
// 在实际应用中,这里可能是一些复杂的计算
return x;
}
// 记忆化搜索函数(在这个例子中,实际上并没有进行搜索,只是展示了记忆化的框架)
int memoizedAdd(std::unordered_map<std::string, int>& memo, int a, int b) {
// 构造一个唯一的键来表示这个特定的计算(在实际应用中,键可能更复杂)
std::string key = std::to_string(a) + "_" + std::to_string(b);
// 检查我们是否已经计算过这个结果
if (memo.find(key) != memo.end()) {
// 如果已经计算过,直接返回结果
return memo[key];
}
// 如果没有计算过,进行计算
int result = complexCalculation(a) + complexCalculation(b);
// 将结果存储在记忆化缓存中
memo[key] = result;
// 返回结果
return result;
}
int main() {
int A, B;
std::cin >> A >> B;
// 创建一个记忆化缓存
std::unordered_map<std::string, int> memo;
// 调用记忆化搜索函数(在这个例子中,它实际上就是简单的加法)
int result = memoizedAdd(memo, A, B);
// 输出结果
std::cout << result << std::endl;
return 0;
}
在这个例子中,memoizedAdd 函数接受一个记忆化缓存(memo)、两个整数A和B,并返回它们的和。我们构造了一个唯一的键来表示这个特定的计算(在这个简单例子中,键是A和B的字符串表示,用下划线分隔)。然后,我们检查这个键是否已经在记忆化缓存中。如果是,我们直接返回缓存中的结果。如果不是,我们进行计算,将结果存储在缓存中,并返回结果。
动态规划转移方法
使用动态规划(Dynamic Programming, DP)来解决。
我们将定义一个DP数组,但实际上我们不会用它来存储中间结果,因为A+B没有中间状态需要保存。不过,为了满足动态规划的形式,我们还是会设置一个DP数组,并展示如何进行状态转移。
以下是一个使用“动态规划转移”方法来解决A+B问题的C++程序(请注意,这里的“动态规划转移”实际上是对大材小用的夸张说法):
#include <iostream>
#include <vector>
int main() {
int A, B;
std::cin >> A >> B;
// 初始化DP数组,大小为1,因为这个问题只有一个状态需要计算(即A+B)
// 实际上,我们不需要这个数组,但为了符合动态规划的形式,我们还是声明了它
std::vector<int> dp(1, 0);
// 假设我们有一个状态转移函数,它实际上只是返回A+B
// 在真正的动态规划问题中,这个函数会根据前面的状态来计算当前状态
auto dpTransition = [&](int a, int b) -> int {
// 这里没有真正的状态转移,只是直接返回A+B
// 在复杂的DP问题中,这里会有逻辑来计算dp[i]基于dp[i-1]或其他前面的状态
return a + b;
};
// 使用“动态规划转移”来计算A+B(实际上就是直接计算)
dp = dpTransition(A, B);
// 输出结果,注意我们只使用dp,因为只有一个状态
std::cout << dp << std::endl;
return 0;
}
在这个程序中,我们定义了一个大小为1的DP数组dp,以及一个模拟状态转移的lambda函数dpTransition。然而,在这个简单的A+B问题中,dpTransition函数只是直接返回了A和B的和,并没有真正进行状态转移。我们还是将结果存储在dp中,并最终输出了它。
请注意,这个程序并没有真正展示动态规划的力量,因为动态规划通常用于解决具有重叠子问题和最优子结构特性的复杂问题。
贪心加广搜方法
使用贪心算法结合广度优先搜索(BFS)通常用于解决一些特定的优化问题,比如图论中的最短路径问题(虽然通常使用Dijkstra算法或Bellman-Ford算法,但在某些情况下可以用贪心加BFS替代)或其他类似问题。然而,对于简单的A+B加法问题,贪心算法和BFS都不是必要的,因为它们通常用于更复杂的问题。
不过,为了满足你的要求,我们可以尝试构造一个问题,其中贪心算法和BFS可以以一种不自然但有趣的方式结合起来,以解决一个类似A+B但稍微复杂一点的问题。比如,我们可以考虑一个场景,其中我们需要找到两个数A和B的和,但这两个数是通过一系列操作从一个初始状态得到的,而这些操作可以用BFS来探索,同时贪心算法可以用来选择最优的操作序列。
但是,直接对A+B问题应用这种方法是牵强的。因此,我将构造一个稍微复杂一点的问题,然后展示如何使用贪心加BFS来解决它。
问题构造:
假设我们有一个整数数组nums和一个目标值target。我们的任务是从数组中选择两个数A和B(A和B可以是同一个数),使得它们的和最接近但不超过target。我们可以对数组中的每个元素进行一次操作:将其增加或减少一个固定的值delta(delta为正整数)。我们希望使用最少的操作次数来达到这个目标。
解决方案:
-
贪心策略:为了尽量减少操作次数,我们希望尽量选择那些已经接近目标和的数。因此,我们可以先对数组进行排序,然后优先考虑那些与目标值最接近的数。
-
广度优先搜索(BFS):我们可以使用BFS来探索所有可能的操作序列。每个状态可以表示为一个元组
(index, current_sum, operations),其中index是当前考虑的数组元素的索引,current_sum是当前选择的数的和,operations是已经执行的操作次数。
然而,这个问题实际上更适合用其他算法(如二分查找加动态规划)来解决,我们将尝试用贪心加BFS的方法。
以下是一个简化的示例代码,它并不完全优化,但展示了如何使用贪心加BFS的思想:
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <climits>
struct State {
int index; // 当前考虑的数的索引
int current_sum; // 当前选择的数的和
int operations; // 已经执行的操作次数
};
int closestSum(std::vector<int>& nums, int target, int delta) {
std::sort(nums.begin(), nums.end()); // 贪心策略:先排序
std::queue<State> q;
q.push({0, 0, 0}); // 初始状态
int closest_sum = -1; // 最接近但不超过target的和
int min_operations = INT_MAX; // 达到最接近和所需的最小操作次数
while (!q.empty()) {
State current = q.front();
q.pop();
if (current.index == nums.size()) {
// 已经考虑了所有数,检查当前和是否是最接近的
if (current.current_sum <= target &&
(closest_sum == -1 || target - current.current_sum < target - closest_sum ||
(target - current.current_sum == target - closest_sum && current.operations < min_operations))) {
closest_sum = current.current_sum;
min_operations = current.operations;
}
continue;
}
// 考虑当前数,有两种选择:加上它或者不加
q.push({current.index + 1, current.current_sum + nums[current.index], current.operations});
// 还可以考虑对当前数进行操作,使其更接近target(这里只考虑增加,减少的情况类似)
// 注意:这里为了简化,我们只考虑增加一次delta,实际上可能需要多次增加或减少
if (current.current_sum + nums[current.index] + delta <= target) {
q.push({current.index + 1, current.current_sum + nums[current.index] + delta, current.operations + 1});
}
// 也可以考虑不选择当前数,直接跳到下一个数
q.push({current.index + 1, current.current_sum, current.operations});
}
return closest_sum;
}
int main() {
std::vector<int> nums = {1, 3, 7, 10};
int target = 15;
int delta = 2;
int result = closestSum(nums, target, delta);
std::cout << "Closest sum to " << target << " is " << result << std::endl;
return 0;
}
请注意,这个示例代码并不完全正确或高效,因为它没有考虑所有可能的操作序列(比如多次增加或减少同一个数)。在实际应用中,可能需要一个更复杂的算法来正确解决这个问题。然而,它展示了如何使用贪心策略(排序)和BFS(探索状态空间)来结合解决一个稍微复杂一点的问题。对于简单的A+B问题,这种方法显然是不必要的,也是低效的。
树方法
使用树结构来解决A+B问题实际上并不是最直接或最高效的方法,因为A+B本身是一个简单的加法运算,不需要复杂的数据结构。我们可以构造一个问题,其中树结构可以用来寻找某个目标值,这个问题与A+B有一定的相似性,但更加复杂。
问题构造:
假设我们有一个二叉树,每个节点都有一个整数值。我们的任务是在这棵树中找到两个节点,使它们的和等于一个给定的目标值。为了增加复杂性,我们可以假设每个节点只能被访问一次,并且我们希望找到这样的节点对,使得从根节点到这两个节点的路径长度之和最小。
解决方案:
-
树的遍历:我们可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来遍历树,并记录每个节点的值和它的路径长度。
-
哈希表:在遍历的过程中,我们可以使用一个哈希表来存储已经访问过的节点的值和对应的路径长度。这样,在访问每个新节点时,我们可以检查哈希表中是否已经存在一个节点,它的值与当前节点的值之和等于目标值。
-
路径长度之和:当我们找到一个节点对,它们的和等于目标值时,我们需要检查从根节点到这两个节点的路径长度之和是否是最小的。如果是,我们更新最小路径长度。
以下是一个简化的示例代码,它展示了如何使用树结构和哈希表来解决这个构造出来的问题:
#include <iostream>
#include <unordered_map>
#include <climits>
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 辅助函数,用于在树中查找节点对,使它们的和等于目标值,并返回最小路径长度之和
int findMinPathLength(TreeNode* root, int target, std::unordered_map<int, int>& valueToPathLength, int currentPathLength, int& minPathLength) {
if (!root) return -1; // 空节点,返回-1
// 计算当前节点到目标值的差值
int complement = target - root->val;
// 检查哈希表中是否已经存在差值,如果存在,则更新最小路径长度
if (valueToPathLength.count(complement)) {
int totalPathLength = currentPathLength + valueToPathLength[complement];
if (totalPathLength < minPathLength) {
minPathLength = totalPathLength;
}
}
// 更新哈希表,记录当前节点的值和路径长度
valueToPathLength[root->val] = currentPathLength;
// 递归遍历左子树和右子树
findMinPathLength(root->left, target, valueToPathLength, currentPathLength + 1, minPathLength);
findMinPathLength(root->right, target, valueToPathLength, currentPathLength + 1, minPathLength);
// 回溯时从哈希表中删除当前节点的值,以便为其他路径腾出空间(可选,取决于具体实现)
valueToPathLength.erase(root->val);
return minPathLength;
}
int main() {
// 构造二叉树
TreeNode* root = new TreeNode(5);
root->left = new TreeNode(3);
root->right = new TreeNode(18);
root->left->left = new TreeNode(2);
root->left->right = new TreeNode(4);
root->right->left = new TreeNode(15);
root->right->right = new TreeNode(20);
int target = 7; // 目标值
int minPathLength = INT_MAX; // 初始化最小路径长度为最大整数值
std::unordered_map<int, int> valueToPathLength; // 哈希表,用于存储节点值和路径长度的映射
// 调用函数查找最小路径长度
int result = findMinPathLength(root, target, valueToPathLength, 0, minPathLength);
if (result != INT_MAX) {
std::cout << "Minimum path length to find two nodes with sum " << target << " is " << result << std::endl;
} else {
std::cout << "No such nodes found." << std::endl;
}
// 释放内存(省略了完整的内存释放逻辑,实际应用中需要确保所有节点都被正确删除)
return 0;
}
请注意,这个示例代码是为了展示如何使用树结构和哈希表来解决一个构造出来的问题,而不是直接解决A+B问题。在实际应用中,对于简单的A+B问题,我们只需要直接计算A和B的和,而不需要使用树或哈希表。
结束了!
对了,忘说了一句话:
要想c++成绩好,就来jiabei小课堂。
还有,点我主页,看我简介,别给那三个人点赞就完了
&spm=1001.2101.3001.5002&articleId=143710426&d=1&t=3&u=2fcf7b38e67c4982911cf195e9f9ab50)
1330

被折叠的 条评论
为什么被折叠?



