You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在总时长内随机排布子时长段?C#实现需求咨询

随机排布子时长段的C#实现优化思路

需求:总时长400秒,需将5秒、90秒、20秒、40秒等子时长段尽可能随机地排布其中。现有代码随机性不足,以下提供两种更优的实现思路及伪代码:

现有代码(C#)

long DurationOccupiedIfArrangedFromLeftWithoutAnyGap = liIntervalsAllocated.Sum();

long startNo = DurationOccupiedIfArrangedFromLeftWithoutAnyGap;
long endNo = TimeInSeconds - liIntervalsAllocated[liIntervalsAllocated.Count - 1];


while (liIntervalsAllocated.Count > 0)
{
      long positionToPlace = CommonFn.GetRandomNumberBetweenTwo((int) startNo, (int) endNo);
      Debug.WriteLine("start No is " + startNo + " End no is " + endNo + " for element selected is " + liIntervalsAllocated[liIntervalsAllocated.Count - 1] + " . ELement is placed at " + positionToPlace);
      
      startNo = startNo - liIntervalsAllocated[liIntervalsAllocated.Count - 1];
      if (liIntervalsAllocated.Count == 1)
      {
          endNo = positionToPlace;
      }
      else
      {
          endNo = positionToPlace - liIntervalsAllocated[liIntervalsAllocated.Count - 2];
      }

      liIntervalsAllocated.RemoveAt(liIntervalsAllocated.Count - 1);
}

优化思路1:间隙分配法(高效且随机性均匀)

核心逻辑:先计算所有子段的总占用时长,得出剩余可分配的总间隙,将总间隙拆分成「子段数量+1」个随机值(分别对应子段前、子段间、子段后的间隙),再按顺序累加间隙和子段得到每个子段的起始位置。

伪代码实现

// 定义子段列表和总时长
var segments = new List<long> { 5, 90, 20, 40 };
long totalDuration = 400;
long totalOccupied = segments.Sum();
long totalGap = totalDuration - totalOccupied;
int gapCount = segments.Count + 1; // 间隙数量 = 子段数 + 1

// 生成总和为totalGap的随机间隙列表
var gaps = GenerateRandomGaps(totalGap, gapCount);

// 计算每个子段的起始位置
long currentPos = 0;
var segmentPositions = new List<(long Start, long Duration)>();
for (int i = 0; i < segments.Count; i++)
{
    currentPos += gaps[i];
    segmentPositions.Add((currentPos, segments[i]));
    currentPos += segments[i];
}

// 辅助方法:生成指定数量、总和固定的非负随机数
List<long> GenerateRandomGaps(long total, int count)
{
    var gaps = new List<long>();
    long remaining = total;
    Random rng = new Random();
    
    for (int i = 0; i < count - 1; i++)
    {
        // 每次随机取0到剩余间隙之间的值
        long gap = rng.NextInt64(0, remaining + 1);
        gaps.Add(gap);
        remaining -= gap;
    }
    gaps.Add(remaining); // 最后一个间隙取剩余值,保证总和正确
    return gaps;
}

优化思路2:随机插入法(直观,适合少量子段)

核心逻辑:先打乱子段顺序,然后逐个随机选择起始位置,检查是否与已放置的子段重叠,不重叠则完成放置。

伪代码实现

var segments = new List<long> { 5, 90, 20, 40 };
long totalDuration = 400;
Random rng = new Random();
var placedSegments = new List<(long Start, long Duration)>();

// 先打乱子段顺序,避免固定顺序影响随机性
foreach (var seg in segments.OrderBy(_ => rng.Next()))
{
    bool isPlaced = false;
    while (!isPlaced)
    {
        long maxStart = totalDuration - seg;
        if (maxStart < 0) throw new InvalidOperationException("总时长不足以容纳所有子段");
        
        // 随机生成起始位置
        long start = rng.NextInt64(0, maxStart + 1);
        long end = start + seg;
        
        // 检查是否与已放置的子段重叠
        bool hasOverlap = placedSegments.Any(p => !(end <= p.Start || start >= p.Start + p.Duration));
        if (!hasOverlap)
        {
            placedSegments.Add((start, seg));
            isPlaced = true;
        }
    }
}

// 可选:按起始位置排序,方便后续处理
placedSegments = placedSegments.OrderBy(p => p.Start).ToList();

两种思路对比

  • 间隙分配法:无需检查重叠,计算效率高,随机性均匀,适合大多数场景,尤其是子段数量较多的情况。
  • 随机插入法:逻辑直观易懂,但子段多、剩余间隙较小时可能会多次重试,适合子段数量少的场景。

原代码的问题在于从右往左放置时,起始和结束范围的限制导致子段容易集中分布,随机性不足,上述两种方法可有效解决该问题。

内容的提问来源于stack exchange,提问作者Sujit Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:14:50