improve:点名算法

改进不放回随机
This commit is contained in:
2025-12-20 19:57:11 +08:00
parent d011d2ba8a
commit 7f01e7acb6
2 changed files with 96 additions and 67 deletions
+52 -48
View File
@@ -537,20 +537,34 @@ namespace Ink_Canvas
bool enableML = MainWindow.Settings?.RandSettings?.EnableMLAvoidance ?? true;
if (!enableML)
{
// 如果禁用机器学习,使用简单随机选择
// 如果禁用机器学习,使用简单不放回随机选择
return SelectNamesRandomly(availableNames, count, random);
}
var candidatePool = new List<string>(availableNames);
var selectedNames = new List<string>();
var remainingNames = new List<string>(availableNames);
for (int i = 0; i < count && remainingNames.Count > 0; i++)
if (count >= candidatePool.Count)
{
string selectedName = SelectSingleNameWithML(remainingNames, selectedNames, random);
return new List<string>(candidatePool);
}
for (int i = 0; i < count && candidatePool.Count > 0; i++)
{
string selectedName = SelectSingleNameWithMLWithoutReplacement(candidatePool, selectedNames, random);
if (!string.IsNullOrEmpty(selectedName))
{
selectedNames.Add(selectedName);
remainingNames.Remove(selectedName);
candidatePool.Remove(selectedName);
}
else
{
if (candidatePool.Count > 0)
{
int randomIndex = random.Next(0, candidatePool.Count);
selectedName = candidatePool[randomIndex];
selectedNames.Add(selectedName);
candidatePool.RemoveAt(randomIndex);
}
}
}
@@ -558,21 +572,34 @@ namespace Ink_Canvas
}
/// <summary>
/// 简单随机选择点名人员
/// 简单不放回随机选择点名人员
/// </summary>
private static List<string> SelectNamesRandomly(List<string> availableNames, int count, Random random)
{
if (availableNames == null || availableNames.Count == 0)
return new List<string>();
var selectedNames = new List<string>();
var remainingNames = new List<string>(availableNames);
for (int i = 0; i < count && remainingNames.Count > 0; i++)
// 如果请求的数量大于或等于可用名单大小,返回所有名单
if (count >= availableNames.Count)
{
int randomIndex = random.Next(remainingNames.Count);
selectedNames.Add(remainingNames[randomIndex]);
remainingNames.RemoveAt(randomIndex);
return new List<string>(availableNames);
}
var candidatePool = new List<string>(availableNames);
var selectedNames = new List<string>();
for (int i = 0; i < count && candidatePool.Count > 0; i++)
{
int randomIndex = random.Next(0, candidatePool.Count);
selectedNames.Add(candidatePool[randomIndex]);
int lastIndex = candidatePool.Count - 1;
if (randomIndex != lastIndex)
{
candidatePool[randomIndex] = candidatePool[lastIndex];
}
candidatePool.RemoveAt(lastIndex);
}
return selectedNames;
@@ -581,10 +608,10 @@ namespace Ink_Canvas
/// <summary>
/// 使用概率算法选择单个人员
/// </summary>
private static string SelectSingleNameWithML(List<string> availableNames, List<string> alreadySelected, Random random)
private static string SelectSingleNameWithMLWithoutReplacement(List<string> candidatePool, List<string> alreadySelected, Random random)
{
if (availableNames.Count == 0) return null;
if (availableNames.Count == 1) return availableNames[0];
if (candidatePool.Count == 0) return null;
if (candidatePool.Count == 1) return candidatePool[0];
// 确保历史数据已初始化
if (historyData == null)
@@ -599,16 +626,16 @@ namespace Ink_Canvas
}
// 过滤掉已选择的人员
var candidateNames = availableNames.Where(name => !alreadySelected.Contains(name)).ToList();
if (candidateNames.Count == 0) return null;
if (candidateNames.Count == 1) return candidateNames[0];
var validCandidates = candidatePool.Where(name => !alreadySelected.Contains(name)).ToList();
if (validCandidates.Count == 0) return null;
if (validCandidates.Count == 1) return validCandidates[0];
// 检查极差:当极差达到3时,从被抽选次数最少的人中抽选
if (historyData.NameFrequency != null && historyData.NameFrequency.Count > 0)
{
// 获取所有候选人员的被抽选次数
var candidateFrequencies = new Dictionary<string, int>();
foreach (string name in candidateNames)
foreach (string name in validCandidates)
{
int count = historyData.NameFrequency.ContainsKey(name) ? historyData.NameFrequency[name] : 0;
candidateFrequencies[name] = count;
@@ -631,7 +658,7 @@ namespace Ink_Canvas
if (leastSelectedNames.Count > 0)
{
// 只从被抽选次数最少的人中随机选择
// 只从被抽选次数最少的人中不放回随机选择
int randomIndex = random.Next(0, leastSelectedNames.Count);
return leastSelectedNames[randomIndex];
}
@@ -639,10 +666,10 @@ namespace Ink_Canvas
}
}
// 获取每个人员的概率
// 获取每个候选人员的概率
var nameProbabilities = new Dictionary<string, double>();
foreach (string name in candidateNames)
foreach (string name in validCandidates)
{
// 获取基础概率
double baseProbability = GetNameProbability(name);
@@ -659,6 +686,7 @@ namespace Ink_Canvas
return ProbabilityBasedRandomSelection(nameProbabilities, random);
}
/// <summary>
/// 获取人员的概率
/// </summary>
@@ -878,30 +906,6 @@ namespace Ink_Canvas
return 1.0 - frequency;
}
/// <summary>
/// 加权随机选择(保留用于兼容,实际已改用概率选择)
/// </summary>
private static string WeightedRandomSelection(Dictionary<string, double> nameWeights, Random random)
{
if (nameWeights.Count == 0) return null;
double totalWeight = nameWeights.Values.Sum();
if (totalWeight <= 0) return nameWeights.Keys.First();
double randomValue = random.NextDouble() * totalWeight;
double currentWeight = 0;
foreach (var kvp in nameWeights)
{
currentWeight += kvp.Value;
if (randomValue <= currentWeight)
{
return kvp.Key;
}
}
return nameWeights.Keys.Last();
}
/// <summary>
/// 更新点名历史记录