当前位置: 首页 > news >正文

CSP-J系列【2024】P11229 [CSP-J 2024] 小木棍题解

题目描述

小 S 喜欢收集小木棍。在收集了 n 根长度相等的小木棍之后,他闲来无事,便用它们拼起了数字。用小木棍拼每种数字的方法如下图所示。

现在小 S 希望拼出一个整数,满足如下条件:

  • 拼出这个数恰好使用 n 根小木棍;
  • 拼出的数没有前导 0;
  • 在满足以上两个条件的前提下,这个数尽可能小。

小 S 想知道这个数是多少,可 n 很大,把木棍整理清楚就把小 S 折腾坏了,所以你需要帮他解决这个问题。如果不存在正整数满足以上条件,你需要输出 −1 进行报告。

输入格式

本题有多组测试数据。

输入的第一行包含一个正整数 T,表示数据组数。

接下来包含 T 组数据,每组数据的格式如下:

一行包含一个整数 n,表示木棍数。

输出格式

对于每组数据:输出一行,如果存在满足题意的正整数,输出这个数;否则输出 −1。

输入输出样例

输入 #1复制

5
1
2
3
6
18

输出 #1复制

-1
1
7
6
208

说明/提示

【样例 1 解释】

  • 对于第一组测试数据,不存在任何一个正整数可以使用恰好一根小木棍摆出,故输出 −1。
  • 对于第四组测试数据,注意 0 并不是一个满足要求的方案。摆出 9、41 以及 111 都恰好需要 6 根小木棍,但它们不是摆出的数最小的方案。
  • 对于第五组测试数据,摆出 208 需要 5+6+7=18 根小木棍。可以证明摆出任何一个小于 208 的正整数需要的小木棍数都不是 18。注意尽管拼出 006 也需要 18 根小木棍,但因为这个数有前导零,因此并不是一个满足要求的方案。

【数据范围】

对于所有测试数据,保证:1≤T≤50,1≤n≤105。

测试点编号n≤特殊性质
120
250
3103A
4,5105A
6103B
7,8105B
9103
10105

特殊性质 A:保证 n 是 7 的倍数且 n≥100。

特殊性质 B:保证存在整数 k 使得 n=7k+1,且 n≥100。

题目概述与分析

小木棍问题是2024年CSP-J竞赛中的一道经典题目,考察选手对搜索算法和剪枝优化的掌握。题目描述有n根长度不同的小木棍,需要将它们拼接成若干根长度相同的长木棍,求可能的最小原始长木棍长度。

这个问题可以建模为组合优化问题,需要综合考虑所有可能的组合方式。我们将介绍两种不同的解法:深度优先搜索(DFS)剪枝法和动态规划法。

解法一:DFS剪枝法

算法思路

  1. 使用深度优先搜索尝试所有可能的组合
  2. 通过多种剪枝策略优化搜索效率
  3. 从最大可能长度开始向下搜索
  4. 时间复杂度取决于剪枝效果,最坏情况下O(n!)
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;vector<int> sticks;
vector<bool> used;
int n, total_len, max_len;bool dfs(int cnt, int cur_len, int start, int target) {if (cnt == total_len / target) return true;if (cur_len == target) return dfs(cnt + 1, 0, 0, target);for (int i = start; i < n; ++i) {if (!used[i] && cur_len + sticks[i] <= target) {if (i > 0 && sticks[i] == sticks[i-1] && !used[i-1]) continue;used[i] = true;if (dfs(cnt, cur_len + sticks[i], i + 1, target)) return true;used[i] = false;if (cur_len == 0) break;}}return false;
}int main() {cin >> n;sticks.resize(n);used.resize(n, false);total_len = 0;max_len = 0;for (int i = 0; i < n; ++i) {cin >> sticks[i];total_len += sticks[i];max_len = max(max_len, sticks[i]);}sort(sticks.begin(), sticks.end(), greater<int>());for (int len = max_len; len <= total_len; ++len) {if (total_len % len != 0) continue;fill(used.begin(), used.end(), false);if (dfs(0, 0, 0, len)) {cout << len << endl;return 0;}}cout << total_len << endl;return 0;
}

该实现使用DFS加多种剪枝策略,包括排序优化、跳过重复值和提前终止等,能有效提高搜索效率。

解法二:动态规划法

算法思路

  1. 将问题转化为背包问题的变种
  2. 使用位运算状态压缩
  3. 记录可达的长度组合
  4. 时间复杂度O(n*sum),适合sum较小的情况
#include <iostream>
#include <vector>
#include <algorithm>
#include <bitset>
using namespace std;int main() {int n;cin >> n;vector<int> sticks(n);int sum = 0;for (int i = 0; i < n; ++i) {cin >> sticks[i];sum += sticks[i];}sort(sticks.begin(), sticks.end());for (int len = sticks.back(); len <= sum; ++len) {if (sum % len != 0) continue;int k = sum / len;vector<bitset<100>> dp(k + 1);dp[0][0] = 1;for (int stick : sticks) {for (int i = k; i >= 0; --i) {for (int j = len; j >= 0; --j) {if (dp[i][j]) {if (j + stick <= len) {dp[i][j + stick] = 1;}if (i + 1 <= k && stick <= len) {dp[i + 1][stick] = 1;}}}}}if (dp[k][0]) {cout << len << endl;return 0;}}cout << sum << endl;return 0;
}

动态规划解法通过状态压缩记录可达的长度组合,适合小规模数据,但空间复杂度较高。

算法对比分析

方法时间复杂度空间复杂度适用场景
DFS剪枝法取决于剪枝效果O(n)数据规模中等,剪枝有效
动态规划法O(n*sum)O(k*len)sum值较小的情况

关键问题详解

剪枝策略优化

  1. 从大到小排序木棍,优先尝试长木棍
  2. 跳过相同长度的重复尝试
  3. 当前组合失败时及时回溯
  4. 限制搜索的起始位置避免重复

边界情况处理

  1. 所有木棍长度相同的情况
  2. 无法分割的情况
  3. 极端大规模数据测试
  4. 包含长度为1的木棍的情况

性能优化建议

  1. 预处理时计算所有可能的候选长度
  2. 使用更高效的数据结构存储状态
  3. 并行化处理可能的候选长度
  4. 提前终止不可能的组合

数学原理分析

  1. 组合数学中的分割问题
  2. 数论中的因数分解应用
  3. 搜索算法的剪枝理论
  4. 动态规划的最优子结构性质

实际应用价值

这类算法在以下领域有重要应用:

  1. 资源分配与调度
  2. 货物装载优化
  3. 时间表安排
  4. 工业生产中的材料切割

扩展思考

  1. 如果木棍有不同颜色限制如何处理?
  2. 如果允许部分不匹配的情况怎么解决?
  3. 如何扩展到三维空间的材料分割?
  4. 多目标优化情况下如何调整算法?

掌握这类组合优化问题的解法,不仅能提升竞赛能力,也对解决实际工程问题有很大帮助。建议先理解基础算法原理,再针对具体问题特点进行优化。

http://www.dtcms.com/a/295078.html

相关文章:

  • 1688官方跨境寻源通API接口调用实战
  • LLM指纹底层技术——混合专家模型
  • CSP-J系列【2023】P9750 [CSP-J 2023] 一元二次方程题解
  • SSH 一键互信配置脚本 V2.0 使用指南
  • 卡尔曼滤波数据融合
  • AI 及开发领域动态与资源汇总(2025年7月23日)
  • 【LeetCode】算法详解#9 ---旋转图像
  • QT开发---基础介绍及环境搭建
  • STM32中SystemCoreClockUpdate函数解读
  • 双写缓冲区 Redo Log
  • 基于GitHub的Terraform自动化管理最佳实践
  • 多服务器批量发布软件
  • Linux编程:9、线程编程-互斥锁与条件变量
  • 扫地机产品的电池CQC认证遵循哪个标准?
  • 1. 一份“从 0 到 1” 的 WSL(Windows Subsystem for Linux)速查手册
  • J2EE模式---视图助手模式
  • ospf多区域
  • git的使用,推送仓库github
  • Hierarchical-Localization 安装与常见问题解决手册
  • MSTP多生成树协议
  • 【西北工业大学公开课】导引系统原理(全61讲)周军 -个人笔记版 5000字
  • 基于多种机器学习的水质污染及安全预测分析系统的设计与实现【随机森林、XGBoost、LightGBM、SMOTE、贝叶斯优化】
  • Parasoft为金融服务打造统一测试平台,提升安全、合规与交付效率
  • Shell函数
  • 无人设备遥控器之无线网络技术篇
  • Linux 一文详谈Vim编辑器的使用
  • 面试150 最大子数组和
  • C语言学习(days09)
  • useEffect
  • Java异常处理核心原理与最佳实践