在研究类似问题时,我遇到了这个问题:最佳添加液体以减少分层。我的解决方案似乎也适用于您的情况。
如果要按30、20、10的比例(即A的30单位,B的20单位和C的10单位)混合液体A,B和C,则最终将全部添加A,然后是所有B,然后是所有C。您最好混合使用较小的单元。例如,按顺序[A,B,A,C,B,A]进行单单元加法。这将完全防止分层。
我发现这样做的方法是使用优先级队列将其视为一种合并。如果我创建一个结构来描述添加的内容:
MergeItem
Item, Count, Frequency, Priority
频率表示为“每N个一个”。因此,六分之三的A的频率为2(6/3)。
并初始化最初包含的堆:
(A, 3, 2, 2)
(B, 2, 3, 3)
(C, 1, 6, 6)
现在,我从堆中删除第一项并将其输出。然后将其计数减少1,并按频率增加Priority,然后将其添加回堆中。产生的堆为:
(B, 2, 3, 0)
(A, 2, 2, 4)
(C, 1, 6, 6)
接下来,从堆中删除B,输出并更新它,然后重新添加到堆中:
(A, 2, 2, 4)
(C, 1, 6, 6)
(B, 1, 3, 6)
如果我以这种方式继续下去,我会得到想要的混合物。我使用一个自定义比较器来确保将相等的优先级项插入堆中时,首先对频率值最高(即频率最小)的项进行排序。
我在博客上写了关于此问题及其解决方案的更完整描述,并提供了一些说明该问题的有效C#代码。请参阅平均分配列表中的项目。
评论后更新
我确实认为我的问题类似于OP的问题,因此我的解决方案可能很有用。抱歉,我对OP的问题不加框框。
第一个反对意见是,我的解决方案使用的是A,B和C,而不是0、1和2,这很容易解决。这只是一个命名问题。我发现思考和说“两个A”而不是“两个1”更容易,也不会造成混淆。但是出于讨论的目的,我在下面修改了我的输出以使用OP的术语。
当然,我的问题涉及距离的概念。如果您想“均匀地散布东西”,则意味着距离。但是,同样,这是我的失败,因为我没有充分展示我的问题与OP的问题有何相似之处。
我使用OP提供的两个示例进行了一些测试。那是:
[1,1,2,2,3,3] // which I converted to [0,0,1,1,2,2]
[0,0,0,0,1,1,1,2,2,3]
在我的术语中,这些分别表示为[2,2,2]和[4,3,2,1]。也就是说,在最后一个示例中,“类型为0的4个项目,类型1的3个项目,类型2的2个项目和类型3的1个项目”。
我运行了测试程序(如下文所述),并发布了结果。缺少OP的输入,我不能说我的结果是否与他的相似,差或好。我也无法将我的结果与其他人的结果进行比较,因为其他人都没有发布任何结果。
但是我可以说,该算法为解决我在混合液体时消除分层的问题提供了一个很好的解决方案。它看起来像它提供了一个合理的解决OP的问题。
对于下面显示的结果,我使用了我在博客条目中详细介绍的算法,将初始优先级设置为Frequency/2
,并修改了堆比较器以支持更频繁的项目。此处显示了修改后的代码,并注释了修改后的行。
private class HeapItem : IComparable<HeapItem>
{
public int ItemIndex { get; private set; }
public int Count { get; set; }
public double Frequency { get; private set; }
public double Priority { get; set; }
public HeapItem(int itemIndex, int count, int totalItems)
{
ItemIndex = itemIndex;
Count = count;
Frequency = (double)totalItems / Count;
// ** Modified the initial priority setting.
Priority = Frequency/2;
}
public int CompareTo(HeapItem other)
{
if (other == null) return 1;
var rslt = Priority.CompareTo(other.Priority);
if (rslt == 0)
{
// ** Modified to favor the more frequent item.
rslt = Frequency.CompareTo(other.Frequency);
}
return rslt;
}
}
使用OP的第一个示例运行测试程序,我得到:
Counts: 2,2,2
Sequence: 1,0,2,1,0,2
Distances for item type 0: 3,3
Stddev = 0
Distances for item type 1: 3,3
Stddev = 0
Distances for item type 2: 3,3
Stddev = 0
因此,我的算法适用于所有数量相等的琐碎问题。
对于OP发布的第二个问题,我得到了:
Counts: 4,3,2,1
Sequence: 0,1,2,0,1,3,0,2,1,0
Distances for item type 0: 3,3,3,1
Stddev = 0.866025403784439
Distances for item type 1: 3,4,3
Stddev = 0.471404520791032
Distances for item type 2: 5,5
Stddev = 0
Distances for item type 3: 10
Stddev = 0
Standard dev: 0.866025403784439,0.471404520791032,0,0
我看不出有明显的改进方法。可以重新排列它以使项目0 [2,3,2,3]的距离或其他一些项目2和3的距离,但这将更改项目1和/或2的偏差。我真的不知道在这种情况下“最佳”。在频率较高或频率较低的项目上偏差较大是否更好?
缺少OP中的其他问题,我用他的描述构成了一些我自己的描述。他在帖子中说:
一个典型的列表有〜50个项目,其中〜15个不同值的数量不同。
所以我的两个测试是:
[8,7,6,5,5,4,3,3,2,2,2,1,1,1,1] // 51 items, 15 types
[12,6,5,4,4,3,3,3,2,2,2,1,1] // 48 items, 13 types
我的结果是:
Counts: 8,7,6,5,5,4,3,3,2,2,2,1,1,1,1
Sequence: 0,1,2,3,4,5,7,6,0,1,2,8,9,10,4,3,0,1,5,2,0,1,3,4,6,7,14,11,13,12,0,2,5,1,0,3,4,2,8,10,9,1,0,7,6,5,3,4,2,1,0
Distances for item type 0: 8,8,4,10,4,8,8,1
Stddev = 2.82566363886433
Distances for item type 1: 8,8,4,12,8,8,3
Stddev = 2.76272565797339
Distances for item type 2: 8,9,12,6,11,5
Stddev = 2.5
Distances for item type 3: 12,7,13,11,8
Stddev = 2.31516738055804
Distances for item type 4: 10,9,13,11,8
Stddev = 1.72046505340853
Distances for item type 5: 13,14,13,11
Stddev = 1.08972473588517
Distances for item type 6: 17,20,14
Stddev = 2.44948974278318
Distances for item type 7: 19,18,14
Stddev = 2.16024689946929
Distances for item type 8: 27,24
Stddev = 1.5
Distances for item type 9: 28,23
Stddev = 2.5
Distances for item type 10: 26,25
Stddev = 0.5
Distances for item type 11: 51
Stddev = 0
Distances for item type 12: 51
Stddev = 0
Distances for item type 13: 51
Stddev = 0
Distances for item type 14: 51
Stddev = 0
对于第二个示例:
Counts: 12,6,5,4,4,3,3,3,2,2,2,1,1
Sequence: 0,1,2,0,3,4,7,5,6,0,1,8,9,10,0,2,0,3,4,1,0,2,6,7,5,12,11,0,1,0,3,4,2,0,1,10,8,9,0,7,5,6,0,
4,3,2,1,0
Distances for item type 0: 3,6,5,2,4,7,2,4,5,4,5,1
Stddev = 1.68325082306035
Distances for item type 1: 9,9,9,6,12,3
Stddev = 2.82842712474619
Distances for item type 2: 13,6,11,13,5
Stddev = 3.44093010681705
Distances for item type 3: 13,13,14,8
Stddev = 2.34520787991171
Distances for item type 4: 13,13,12,10
Stddev = 1.22474487139159
Distances for item type 5: 17,16,15
Stddev = 0.816496580927726
Distances for item type 6: 14,19,15
Stddev = 2.16024689946929
Distances for item type 7: 17,16,15
Stddev = 0.816496580927726
Distances for item type 8: 25,23
Stddev = 1
Distances for item type 9: 25,23
Stddev = 1
Distances for item type 10: 22,26
Stddev = 2
Distances for item type 11: 48
Stddev = 0
Distances for item type 12: 48
Stddev = 0