带依赖的4000个序列测试用例按10%/30%/30%/30%分配的算法咨询
解决带依赖的测试用例序列比例分组问题
嘿,这个问题本质上是带依赖约束的多组背包问题,再加上序列不可拆分的硬性要求,我来给你拆解一套可行的解决方案,完全贴合你提到的10%/30%/30%/30%占比目标:
第一步:先把依赖关系和序列信息理清楚
首先得把核心的基础信息整理到位,否则后续都是空中楼阁:
- 先统计每个序列(比如s1-s50)包含的测试用例数量,记为每个序列的「大小」;
- 梳理序列间的依赖关系:比如s3必须在s7之前执行,或者s5和s9是强绑定必须同组?这里默认是执行顺序依赖(即依赖的序列必须在被依赖序列的前面集合或同集合),而且不能有循环依赖(如果有,得先把循环里的序列合并成一个不可拆分的大单元,否则测试用例根本没法跑);
- 把这些依赖关系转换成有向无环图(DAG),然后做一次拓扑排序,得到一个满足依赖顺序的序列列表——这样后续分组的时候,只要按这个顺序来,就不会打破依赖规则。
第二步:用动态规划+启发式搜索做分组优化
因为我们的目标是把序列分成4组,每组大小尽可能接近400、1200、1200、1200(对应4000总用例的比例),这里分两种场景处理:
场景1:集合是按执行顺序排列的(前一个集合跑完才能跑后一个)
这种情况最常见,比如测试是分阶段执行的。我们可以用前缀和+贪心+局部调整的方式快速找到近似最优解:
- 先算拓扑排序后的序列前缀和数组,比如
prefix_sum[m]表示前m个序列的总测试用例数; - 找第一个集合:找最小的m1,让
prefix_sum[m1]尽可能接近400——比如如果前3个序列总和是380,前4个是420,那先选前3个,或者试试把第4个序列里有没有可能拆分?不行,序列不可拆分,那选380或者420,看哪个偏差小; - 然后在剩下的序列里找第二个集合:让这个子集的总和尽可能接近1200,同样用前缀和找边界;
- 第三个集合同理,剩下的归为第四个;
- 如果初始分组的偏差太大(比如第四个集合只有1000),就做局部调整:比如把第二个集合末尾的一个小序列移到第三个,或者把第一个集合的一个大序列移到第二个,重新计算总偏差,选最优的组合。
场景2:集合内可以包含非连续的序列(只要依赖满足)
如果你的测试框架允许集合内的序列乱序执行(只要依赖的序列在更早的集合里),那可以用带约束的多目标动态规划:
- 定义DP状态:
dp[m][a][b][c]表示前m个序列,第一个集合总大小是a,第二个是b,第三个是c,第四个就是前m个的总和减去a+b+c; - 状态转移:对于第m+1个序列,我们可以把它放到四个集合中的任意一个,但必须满足:如果这个序列依赖某个已分配的序列,那它的集合编号不能比依赖序列的集合编号小;
- 目标是最小化四个集合大小与目标值的偏差平方和(比如
(sum1-400)² + (sum2-1200)² + ...),这样能保证整体偏差最小。
第三步:局部迭代优化
不管用哪种方法得到初始分组,都可以做一轮局部调整来缩小偏差:
- 检查每个集合的偏差,把相邻集合边界附近的小序列来回移动,看看能不能让总偏差变小;
- 比如如果第一个集合是390(差10),第二个是1220(超20),那看看第二个集合开头有没有一个大小为10的序列,移到第一个集合,这样两个集合的偏差都变成0,完美。
拿你给的例子验证一下
你说的序列大小是[14,17,25,11,14,14,5],总大小100,目标是10、30、30、30:
- 拓扑排序后假设顺序不变;
- 第一个集合找接近10的,选11(偏差+1);
- 剩下的序列里找接近30的,14+14+5=33(偏差+3);
- 再剩下的找接近30的,14+17=31(偏差+1);
- 最后剩下25(偏差-5);
- 总偏差平方和是1+9+1+25=36,这就是你提到的最优组合,完全符合预期。
内容的提问来源于stack exchange,提问作者Selva
相关产品推荐
相关产品推荐

