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

如何用C#自动生成含多停站与多轮胎配方的最优赛车策略

问题描述

我正在编写C#脚本,计算40圈赛事的最短完成时间,需要结合轮胎配方(软胎、中性胎)与进站策略(进站间隔圈数,称为segment)。当前脚本暴力枚举1次进站的所有可行组合(单段圈数不超过25,共20种轮胎与段数组合),但扩展至2次进站(3段)策略时,手动实现方式不再可行。请问是否存在更高效的方法来生成并遍历所有可行赛车策略?能否自动生成策略而非手动列举?

以下是当前脚本(因用于数学论文,使用decimal而非double):

using System;
using System.Collections.Generic;
using System.Linq;
                    
public class Program
{
    public static void Main()
    {
        List<decimal> findMin = new List<decimal>();

        //Add all possible values to the list 
        for(int i = 25; i >= 20; i--)
        {
            findMin.Add(LowestCombo(i, 40 - i));
        }

        Console.WriteLine(" ");

        //Print lowest number in the list
        Console.WriteLine($"The lowest possible time achievable is {findMin.Min()}");

    }
    public static decimal LowestCombo (int a, int b){
        List<decimal> sumBoth = new List<decimal>();
        string[] identifier = {"all soft tyres", "all medium tyres", "soft, then medium", "medium, then soft"};

        //Add all possible combinations of the two to the list
        sumBoth.Add(SoftSummation(a) + SoftSummation(b));
        sumBoth.Add(MedSummation(a) + MedSummation(b));
        sumBoth.Add(SoftSummation(a) + MedSummation(b));
        sumBoth.Add(MedSummation(a) + SoftSummation(b));
        
        //Print the combination of laps and tyres as well as the time, then return the lowest time
        Console.WriteLine($"The lowest possible time achievable with {a} initial laps and {b} final laps for a 1 pit stop race is {sumBoth.Min()}, {identifier[sumBoth.IndexOf(sumBoth.Min())]}.");
        return sumBoth.Min();
    }

    
    public static decimal SoftSummation(int a)
    {   
        decimal sum = 0;
        
            for(int x = 1; x <= a; x++)
            {
                //Tyre degradation function for the soft compound (Math.Pow can't take decimal??)
                sum += (0.1262m * (x * x * x * x)) - (4.476m * (x * x * x)) + (56.37m * (x * x)) - (152.9m * x) + (1.427m * (100000m));
            }
        
        return sum; 
    }

    
    public static decimal MedSummation(int a)
    {   
        decimal sum = 0;
        
            for(int x = 1; x <= a; x++)
            {
                //Tyre degradation function for the medium compound
                sum += (0.8406m * (x * x)) + (44.77m * x) + (1.434m * 100000m);
            }
        
        return sum; 
    }
}
解决方案

1. 抽象轮胎逻辑并预计算单圈时间

先把轮胎类型抽象成枚举,同时预计算每圈的时间(避免重复求和),后续扩展轮胎类型只需添加新的预计算逻辑:

public enum TyreType { Soft, Medium }

// 预存储每种轮胎的单圈时间(1到40圈)
private static readonly Dictionary<TyreType, List<decimal>> _tyreLapTimes = new Dictionary<TyreType, List<decimal>>();

// 初始化预计算数据
static Program()
{
    // 计算软胎每圈时间
    var softTimes = new List<decimal>();
    for (int lap = 1; lap <= 40; lap++)
    {
        decimal time = (0.1262m * (decimal)Math.Pow(lap, 4)) 
                      - (4.476m * (decimal)Math.Pow(lap, 3)) 
                      + (56.37m * lap * lap) 
                      - (152.9m * lap) 
                      + (1.427m * 100000m);
        softTimes.Add(time);
    }
    _tyreLapTimes[TyreType.Soft] = softTimes;

    // 计算中性胎每圈时间
    var medTimes = new List<decimal>();
    for (int lap = 1; lap <= 40; lap++)
    {
        decimal time = (0.8406m * lap * lap) 
                      + (44.77m * lap) 
                      + (1.434m * 100000m);
        medTimes.Add(time);
    }
    _tyreLapTimes[TyreType.Medium] = medTimes;
}

// 计算某段连续圈数的总时间(轮胎从第1圈开始磨损)
public static decimal CalculateSegmentTime(TyreType tyre, int segmentLaps)
{
    decimal total = 0;
    for (int i = 0; i < segmentLaps; i++)
    {
        total += _tyreLapTimes[tyre][i];
    }
    return total;
}

2. 自动生成所有合法分段组合

通过递归生成任意进站次数对应的分段组合,自动满足「单段圈数≤25、总圈数=40、每段至少1圈」的规则:

// 生成指定进站次数的所有合法分段
public static List<List<int>> GenerateSegments(int totalLaps, int pitStopCount, int maxLapsPerSegment)
{
    var result = new List<List<int>>();
    int segmentCount = pitStopCount + 1;
    GenerateSegmentsRecursive(totalLaps, segmentCount, maxLapsPerSegment, new List<int>(), result);
    return result;
}

private static void GenerateSegmentsRecursive(int remainingLaps, int remainingSegments, int maxPerSegment, List<int> current, List<List<int>> result)
{
    if (remainingSegments == 1)
    {
        if (remainingLaps >= 1 && remainingLaps <= maxPerSegment)
        {
            var final = new List<int>(current);
            final.Add(remainingLaps);
            result.Add(final);
        }
        return;
    }

    // 每段至少1圈,且剩余段数需保留至少1圈的余量
    int end = Math.Min(maxPerSegment, remainingLaps - (remainingSegments - 1));
    for (int i = 1; i <= end; i++)
    {
        current.Add(i);
        GenerateSegmentsRecursive(remainingLaps - i, remainingSegments - 1, maxPerSegment, current, result);
        current.RemoveAt(current.Count - 1);
    }
}

3. 生成所有轮胎组合并计算最优解

通过笛卡尔积生成所有轮胎搭配,遍历所有分段+轮胎的组合,计算总时间并记录最小值:

public static void FindOptimalStrategy(int totalLaps, int pitStopCount, int maxLapsPerSegment)
{
    int segmentCount = pitStopCount + 1;
    var segments = GenerateSegments(totalLaps, pitStopCount, maxLapsPerSegment);
    var tyreTypes = Enum.GetValues(typeof(TyreType)).Cast<TyreType>().ToList();

    decimal minTotalTime = decimal.MaxValue;
    List<int> bestSegments = null;
    List<TyreType> bestTyreCombo = null;

    foreach (var segment in segments)
    {
        // 生成该分段对应的所有轮胎组合
        var tyreCombos = GenerateTyreCombinations(tyreTypes, segmentCount);
        foreach (var tyres in tyreCombos)
        {
            decimal totalTime = 0;
            for (int i = 0; i < segmentCount; i++)
            {
                totalTime += CalculateSegmentTime(tyres[i], segment[i]);
            }

            // 更新最优策略
            if (totalTime < minTotalTime)
            {
                minTotalTime = totalTime;
                bestSegments = segment;
                bestTyreCombo = tyres;
            }
        }
    }

    // 输出结果
    Console.WriteLine($"最优策略({pitStopCount}次进站):");
    Console.WriteLine($"总时间:{minTotalTime}");
    Console.WriteLine("分段详情:");
    for (int i = 0; i < bestSegments.Count; i++)
    {
        Console.WriteLine($"第{i+1}段:{bestSegments[i]}圈,{bestTyreCombo[i]}胎");
    }
}

// 生成指定长度的轮胎组合(笛卡尔积)
public static List<List<TyreType>> GenerateTyreCombinations(List<TyreType> tyreTypes, int length)
{
    if (length == 0)
    {
        return new List<List<TyreType>> { new List<TyreType>() };
    }

    var result = new List<List<TyreType>>();
    var subCombos = GenerateTyreCombinations(tyreTypes, length - 1);
    foreach (var combo in subCombos)
    {
        foreach (var tyre in tyreTypes)
        {
            var newCombo = new List<TyreType>(combo);
            newCombo.Add(tyre);
            result.Add(newCombo);
        }
    }
    return result;
}

4. 调用示例

在Main方法中直接调用即可计算任意进站次数的最优策略:

public static void Main()
{
    // 计算2次进站(3段)的最优策略
    FindOptimalStrategy(40, 2, 25);
}

核心优势

  • 自动适配任意进站次数:无需手动修改代码,传入进站次数即可生成对应分段
  • 预计算提升效率:避免重复计算单圈时间,减少冗余运算
  • 全组合覆盖:自动生成所有合法的分段和轮胎搭配,不会遗漏最优解

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:57:02