用动画解释这个代码:// Andy 2024-07-26 Trae AI #include // 用于标准输入输出 #include // 用于动态数组 std::vector #include // 用于 std::accumulate (虽然本代码未使用,但通常与数值处理相关) #include // 用于 std::sort #include // 用于 std::memset int n_pieces; // 小木棍的总数量 std::vector stick_lengths; // 存储每根小木棍长度的动态数组 bool used[65]; // 标记某根小木棍是否已被使用(题目保证数量不超过64) int current_target_len; // 当前枚举的原始木棒的目标长度 int num_original_sticks_to_form; // 根据 current_target_len 计算出需要拼成的原始木棒数量 /** * @brief 使用深度优先搜索 (DFS) 和剪枝策略来解决问题。 * * @param u 当前已经成功拼成的原始木棒的数量。 * @param current_partial_stick_len 当前正在拼凑的这根原始木棒已经达到的长度。 * @param search_start_idx 本次搜索小木棍时,在 stick_lengths 数组中开始搜索的起始索引。 * 用于确保在拼凑同一根原始木棒时,小木棍按索引递增顺序选取,避免重复组合。 * @return true 如果能够用所有小木棍成功拼成 num_original_sticks_to_form 根长度为 current_target_len 的原始木棒,则返回 true;否则返回 false。 */ bool solve_dfs(int u, int current_partial_stick_len, int search_start_idx) { // 基本情况:所有原始木棒都已成功拼成 if (u == num_original_sticks_to_form) { return true; // 找到了一个可行的方案 } // 当前这根原始木棒已经拼凑完成,尝试开始拼凑下一根 if (current_partial_stick_len == current_target_len) { // 递归调用,目标是拼凑第 u+1 根原始木棒 (u 从0开始计数) // 新的这根木棒当前长度为0,并且从头开始搜索可用的小木棍 (search_start_idx = 0) return solve_dfs(u + 1, 0, 0); } // 遍历可用的小木棍,尝试将它们加入到当前正在拼凑的原始木棒中 for (int i = search_start_idx; i < n_pieces; ++i) { if (used[i]) continue; // 如果这根小木棍已经被用过了,则跳过 // 如果当前小木棍的长度加上正在拼凑的木棒的当前长度,不超过目标长度 if (current_partial_stick_len + stick_lengths[i] <= current_target_len) { used[i] = true; // 标记这根小木棍为已使用 // 递归地尝试完成当前木棒或移动到下一根木棒 // 对于 *同一根* 原始木棒,下一根小木棍必须从索引 i+1 开始选择, // 以避免对同一组小木棍的不同排列进行重复计算(例如 {1,2,3} 和 {1,3,2})。 if (solve_dfs(u, current_partial_stick_len + stick_lengths[i], i + 1)) { return true; // 如果后续的递归调用找到了一个解,则当前选择是可行的 } used[i] = false; // 回溯:取消标记这根小木棍为已使用,尝试其他可能性 // --- 剪枝策略 --- // 剪枝1:新木棒的第一根小木棍选择失败 // 如果我们正在尝试为一根新的原始木棒放置第一根小木棍 (current_partial_stick_len == 0), // 并且使用 stick_lengths[i] (当前能选的最大的一根,因为已排序) 无法导出解, // 那么对于当前的 current_target_len,不可能找到解。因为如果最大的都不能作为开头,其他更小的也不能。 if (current_partial_stick_len == 0) { return false; } // 剪枝2:恰好拼完一根木棒后,后续失败 // 如果加入 stick_lengths[i] 恰好完成了当前这根原始木棒 // (即 current_partial_stick_len + stick_lengths[i] == current_target_len), // 但是后续的递归调用(即上面 current_partial_stick_len == current_target_len 分支触发的 solve_dfs(u + 1, 0, 0))失败了, // 这意味着即使当前这根木棒能拼成,也无法完成整个任务。因此,当前的 current_target_len 不可行。 if (current_partial_stick_len + stick_lengths[i] == current_target_len) { return false; } // 剪枝3:跳过因相同长度而导致重复失败的小木棍 // 如果对于当前状态 (u, current_partial_stick_len),使用 stick_lengths[i] 无法导出解, // 那么对于任何后续的、长度与 stick_lengths[i] 相同的 stick_lengths[j] (其中 j > i), // 在当前这个状态下也必然无法导出解。因此,可以跳过这些等长的小木棍。 while (i + 1 < n_pieces && stick_lengths[i+1] == stick_lengths[i]) { i++; // 跳到下一个不同长度的小木棍,或者数组末尾 } } } // 如果遍历了所有可用的小木棍都无法完成当前木棒的拼凑,或者无法形成所有木棒 return false; } int main() { // 优化C++标准库的输入输出性能 std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); // 循环处理多组测试数据,直到输入 n_pieces 为 0 while (std::cin >> n_pieces && n_pieces != 0) { stick_lengths.resize(n_pieces); // 根据小木棍数量调整vector大小 int total_sum = 0; // 所有小木棍的总长度 int max_indiv_stick_len = 0; // 单根小木棍的最大长度 // 读取每根小木棍的长度,并计算总长度和最大单根长度 for (int i = 0; i < n_pieces; ++i) { std::cin >> stick_lengths[i]; total_sum += stick_lengths[i]; if (stick_lengths[i] > max_indiv_stick_len) { max_indiv_stick_len = stick_lengths[i]; } } // 将小木棍按长度从大到小排序,这有助于剪枝(优先尝试较大的木棍) std::sort(stick_lengths.rbegin(), stick_lengths.rend()); // 枚举所有可能的原始木棒长度 (current_target_len 的候选值) // 原始木棒的最小可能长度是所有小木棍中最长的那一根的长度。 // 原始木棒的最大可能长度是所有小木棍的总长度(即只有一根原始木棒的情况)。 for (int len_cand = max_indiv_stick_len; len_cand <= total_sum; ++len_cand) { // 检查候选长度是否能被总长度整除,这是成为合法原始木棒长度的必要条件 if (total_sum % len_cand == 0) { current_target_len = len_cand; // 设置当前尝试的原始木棒目标长度 num_original_sticks_to_form = total_sum / current_target_len; // 计算需要拼成的原始木棒数量 std::memset(used, false, sizeof(used)); // 为新的目标长度重置 'used' 数组,所有小木棍标记为未使用 // 开始DFS搜索: // 初始状态:0根原始木棒已拼成,当前正在拼的木棒长度为0,从索引0开始搜索小木棍 if (solve_dfs(0, 0, 0)) { std::cout << current_target_len << std::endl; // 找到最小的可能长度,输出 goto next_test_case; // 跳转到处理下一组测试数据 } } } next_test_case:; // 标签,用于 goto 跳转 } return 0; // 程序正常结束 }

视频信息