问题描述
有点新手用这些东西,但我不知道为什么我不能用Microsoft Solver Foundation解决这个看似简单的问题,有人请求帮助!
Bit of a newbie with this stuff but I'm at a loss as to why I can't get this seemingly simple problem solved using Microsoft Solver Foundation, someone please help!
我需要的是修改某些观察的权重(数字),以确保没有1个观察者的体重超过25%。这是为了稍后使用此算法的结果计算约束加权平均值。
All I need is to modify the weights (numbers) of certain observations to ensure that no 1 observation's weight AS A PERCENTAGE exceeds 25%. This is for the purposes of later calculating a constrained weighted average with the results of this algorithm.
例如,给定{45,100,33,500,28}的5个权重,我希望这个算法的结果是{45,
53 ,33, 53 ,28},其中2个数字必须减少,他们在新总数的25%门槛范围内( 212 = 45 + 53 + 33 + 53 + 28),而其他人则保持不变。
For example, given the 5 weights of { 45, 100, 33, 500, 28 }, I would expect the result of this algorithm to be { 45,53, 33, 53, 28 }, where 2 of the numbers had to be reduced such that they're within the 25% threshold of the new total (212 = 45+53+33+53+28) while the others remained untouched.
我尝试使用Solver(请参阅下面的代码)重新创建这个简单的示例,仅仅是因为它告诉我解决方案是"不可行"的。它只返回所有1。对此有任何帮助将非常感谢,提前感谢。
I tried to recreate this simple example using Solver (please see code below) only for it to tell me that it is the solution is "Infeasible" and it just returns all 1s. Any help with this would be very much appreciated, thanks in advance.
PS 解决方案无需使用Solver,任何正确工作的替代方案都是受欢迎的,只要它在处理时速度很快相当数量的权重。
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
var decisionList = new List<Decision>();
decisionList.Add(new Decision(Domain.IntegerRange(1, 45), "Dec1"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 100), "Dec2"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 33), "Dec3"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 500), "Dec4"));
decisionList.Add(new Decision(Domain.IntegerRange(1, 28), "Dec5"));
model.AddDecisions(decisionList.ToArray());
int weightLimit = 25;
foreach (var decision in model.Decisions)
{
model.AddConstraint(decision.Name + "weightLimit", 100 * (decision / Model.Sum(model.Decisions.ToArray())) <= weightLimit);
}
model.AddGoal("calcGoal", GoalKind.Maximize, Model.Sum(model.Decisions.ToArray()));
var solution = solver.Solve();
foreach (var decision in model.Decisions)
{
Debug.Print(decision.GetDouble().ToString());
}
Debug.Print("Solution Quality: " + solution.Quality.ToString());
推荐答案
Dim numbers As New List(Of Integer) From {45, 100, 33, 500, 28}
numbers.Sort()
numbers.Reverse() 'should be in descending order now
Dim threshold As Decimal = 0.25
Dim increment As Integer = 1
For i As Integer = 0 To numbers.Count - 1
Do Until numbers(i) / numbers.Sum <= threshold
For j As Integer = i To 0 Step -1
Do Until numbers(j) / numbers.Sum <= threshold
numbers(j) -= increment
Loop
Next
Loop
Next
Dim results As String = ""
For Each num As Integer In numbers
results += num.ToString & " / " & numbers.Sum.ToString & " = " & (num / numbers.Sum).ToString("F4") & Environment.NewLine
Next
MessageBox.Show(results)
P.S。谢谢你让我伸展自己的大脑。仔细考虑这一点非常令人耳目一新。
P.S. Thank you for letting my stretch my brain. This was quite refreshing to think through.
编辑2:
这是C#有一些补充。它还存储原始值(排序后)以便在结尾显示。
Here is the C# with some additions. It also stores the original values (after sorting) for display at the end.
List<int> numbers = new List<int> {45,100,33,500,28,89,5,1359,23549};
numbers.Sort();
numbers.Reverse(); //should be in descending order now
List<int> original = new List<int>();
original.AddRange(numbers);
decimal threshold = 0.25M;
int increment = 1;
for (int i = 0; i < numbers.Count; i++)
{
while (!((decimal)numbers[i] / numbers.Sum() <= threshold))
{
for (int j = i; j >= 0; j--)
{
while (!((decimal)numbers[j] / numbers.Sum() <= threshold))
{
numbers[j] -= increment;
}
}
}
}
string results = "";
for (int i = 0; i < numbers.Count; i++)
{
results += "Original: " + original[i].ToString() + " \t Calc: " + numbers[i].ToString() + " / " + numbers.Sum().ToString() + " = " + ((decimal)numbers[i] / numbers.Sum()).ToString("F4") + Environment.NewLine;
}
MessageBox.Show(results);
这篇关于带有/不带解算器的C#简约约束加权平均算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!