我正在尝试将数字拆分为适合预定义范围的较小数字,而我似乎无法使算法正确。我正在使用C#。
示例
将 20 分成三个数字,其中数字必须符合以下范围: 1-3,3-10和0-15 。最终数字可能如下所示:1,5,14或2,3,15
另一个例子可能是将 100 分成四个符合以下范围的数字: 0-10,0-10,0-40,0-40 。结果自然是10,10,40,40。在相同的范围内拆分90可能会产生5,8,38,39等。
你能帮助我朝正确的方向发展吗?
(不,这不是作业,而是个人项目)
答案 0 :(得分:1)
以下描述了一种非常有效的方法,假设存储桶具有某种排序。
首先选择每个范围的最小值并将其相加。
接下来,从每个范围中减去最小值,使它们全部归一化为0。 。 n并从您的数字中减去总和。这不是绝对必要的,但它有助于解释算法的其余部分。
接下来,执行最大范围值的累积和。找到新总和适合的水桶(对于之前的水桶来说太大但适合)。如果没有找到,则发出错误。
然后分配箱子,使前面的桶达到最大值,并将找到的桶设置为适当的值。
这为您提供了一组符合您条件的值。
如果想要在范围的“中间”中更多的值,则从范围的中间值开始。然后在所有存储桶中以块的形式添加或减去值,直到达到最大值。这需要多一点迭代,但它也非常有效。
答案 1 :(得分:1)
试试这个:
List<KeyValuePair<int, int>> ranges = new List<KeyValuePair<int, int>>();
ranges.Add(new KeyValuePair<int, int>(1, 3));
ranges.Add(new KeyValuePair<int, int>(1, 3));
ranges.Add(new KeyValuePair<int, int>(1, 100));
int totalSum = ranges.Sum(i => i.Value - i.Key);
double ws = 0.0;
int rIndex = 0;
var rangeAndWeight = ranges.Select(i => new { index = rIndex++, range = i, maxw = (ws += (double)(i.Value - i.Key) / totalSum) }).ToList();
int[] nums = ranges.Select(i => i.Key).ToArray();
int number = 50;
Random r = new Random();
while (nums.Sum() != number)
{
double rDouble = r.NextDouble();
var index = rangeAndWeight.SkipWhile(i => i.maxw < rDouble).First().index;
if (nums[index] < ranges[index].Value)
nums[index] += 1;
}
nums
数组包含您需要的较小数字
答案 2 :(得分:1)
您可以使用递归来完成。
算法的想法是这样的:
在每次执行中,您将迭代所有可能的间隔数。
递归调用以生成下一个间隔的下一个数字。
如果总和超过所需的值,则返回。
一旦生成了所有数字,如果总和等于所需的数字,那么您就有了可能的组合。
它可以改进,但它是一种解决方案。
以下代码在控制台中打印所有有效序列:
SplitNumber(100, new Interval[]
{
new Interval { Min = 0, Max = 11 },
new Interval { Min = 0, Max = 11 },
new Interval { Min = 0, Max = 40 },
new Interval { Min = 0, Max = 40 },
});
public static void SplitNumber(int n, Interval[] intervals)
{
SplitNumber(n, 0, intervals, "");
}
public static void SplitNumber(int n, int k, Interval[] intervals, string s)
{
if (n < 0) return;
if (k >= intervals.Length) { if (n == 0) Console.WriteLine(s); }
else
for (int i = intervals[k].Min; i <= intervals[k].Max; i++)
SplitNumber(n - i, k + 1, intervals, string.Format("{0} {1}", s, i));
}
Interval
类是这样的:
public class Interval
{
public int Min { get; set; }
public int Max { get; set; }
}
答案 3 :(得分:0)
您可以编写一个程序,只是尝试在允许的范围内总结可能的数字,并希望结果是正确的,如果结果错误则回溯。它非常无用......