C# 6米钢筋切割长度优化程序问题排查求助
问题排查与修复方案
原代码的核心问题
- 索引错误导致元素被跳过:在
for循环中执行RemoveAt(i)后,列表长度缩短,但i仍会递增,导致下一个元素被跳过,无法检查是否能加入当前组。比如原列表降序后是3200,3100,2900,2700,...,第一次处理完3200(i=0)后,移除元素,i变为1,直接跳过了3100的检查。 - 局部贪心的局限性:原算法每次优先加最大元素,会错过全局更优的组合(比如
3100+2900=6000余料为0的组合)。 - 组构建不彻底:仅遍历一次列表就结束组构建,导致可加入当前组的小元素被遗漏(比如最后一组的800本可和1200、670合并)。
修复后的基础版本(解决索引问题)
先解决元素被跳过的问题,确保每个元素都能被正确检查:
const int BAR_LENGTH = 6000; List<int> cuts = new() { 3200, 800, 3100, 2900, 1200, 690, 2700, 1200, 1100, 980, 670 }; List<string> cutsOptimized = new(); cuts.Sort(); cuts.Reverse(); int cutSum = 0; string cutGroup = ""; while (cuts.Count > 0) { for (int i = 0; i < cuts.Count; i++) { if (cutSum + cuts[i] <= BAR_LENGTH) { cutSum += cuts[i]; cutGroup += cuts[i].ToString() + ","; cuts.RemoveAt(i); i--; // 修复索引,避免跳过元素 } } // 移除末尾多余的逗号 if (!string.IsNullOrEmpty(cutGroup)) { cutGroup = cutGroup.TrimEnd(','); } cutsOptimized.Add(cutGroup); cutGroup = ""; cutSum = 0; } Console.WriteLine(string.Join(Environment.NewLine, cutsOptimized));
优化版本(优先匹配无余料组合)
为了得到更优的结果,先优先处理刚好凑成6000的组合(余料为0),再用修复后的贪心算法处理剩余元素:
const int BAR_LENGTH = 6000; List<int> cuts = new() { 3200, 800, 3100, 2900, 1200, 690, 2700, 1200, 1100, 980, 670 }; List<string> cutsOptimized = new(); // 先处理两两凑整的最优组合 for (int i = cuts.Count - 1; i >= 0; i--) { int target = BAR_LENGTH - cuts[i]; int matchIndex = cuts.IndexOf(target); if (matchIndex != -1 && matchIndex != i) { cutsOptimized.Add($"{cuts[i]},{cuts[matchIndex]}"); // 先移除索引大的元素,避免索引错乱 cuts.RemoveAt(Math.Max(i, matchIndex)); cuts.RemoveAt(Math.Min(i, matchIndex)); i--; // 移除元素后调整索引 } } // 剩余元素降序排序,用修复后的贪心算法处理 cuts.Sort(); cuts.Reverse(); int cutSum = 0; string cutGroup = ""; while (cuts.Count > 0) { bool added = false; for (int i = 0; i < cuts.Count; i++) { if (cutSum + cuts[i] <= BAR_LENGTH) { cutSum += cuts[i]; cutGroup += cuts[i].ToString() + ","; cuts.RemoveAt(i); i--; added = true; } } // 处理无法再添加元素的剩余单个元素 if (!added) { cutGroup += cuts[0].ToString(); cuts.RemoveAt(0); } cutGroup = cutGroup.TrimEnd(','); cutsOptimized.Add(cutGroup); cutGroup = ""; cutSum = 0; } Console.WriteLine(string.Join(Environment.NewLine, cutsOptimized));
这个版本会优先输出3100,2900(余料0),再输出3200,2700(余料100),后续组合的余料也会更小,符合预期。
关键说明
- 索引修复是基础:移除元素后
i--,确保每个元素都能被检查到。 - 优先凑整是简单有效的优化:在贪心算法基础上,先锁定无余料的最优组合,大幅减少总余料。
- 代码保持简洁:没有使用复杂算法(如动态规划),适合入门开发者理解和修改。
内容的提问来源于stack exchange,提问作者PhiCato
相关产品推荐
相关产品推荐

