Benzer bir problemi araştırırken bu soruyla karşılaştım: tabakalaşmayı azaltmak için optimum sıvı ilavesi. Çözümüm sizin durumunuz için de geçerli olacak gibi görünüyor.
A, B ve C sıvılarını 30,20,10 (30 birim A, 20 birim B ve 10 birim C) oranında karıştırmak istiyorsanız, hepsini ekleyin. A, sonra tüm B ve sonra tüm C. Küçük birimleri karıştırmaktan daha iyi olursunuz. Örneğin, [A, B, A, C, B, A] dizisindeki tek birimli eklemeler yapın. Bu tamamen tabakalaşmayı önleyecektir.
Bunu yapmamın yolu, öncelik sırasını kullanarak bir çeşit birleştirme gibi davranmak. Eklemeleri tanımlamak için bir yapı oluşturursam:
MergeItem
Item, Count, Frequency, Priority
Frekans "her N bir" olarak ifade edilir. Öyleyse altı defadan üçüne eklenen A, 2 (6/3) sıklığına sahiptir.
Ve başlangıçta içeren bir öbek başlat:
(A, 3, 2, 2)
(B, 2, 3, 3)
(C, 1, 6, 6)
Şimdi ilk öğeyi öbekten kaldırıyorum ve çıkarıyorum. Ardından sayısını 1 azaltın ve Önceliği Frekansla artırın ve tekrar yığına ekleyin. Sonuçta ortaya çıkan yığın:
(B, 2, 3, 0)
(A, 2, 2, 4)
(C, 1, 6, 6)
Ardından, B'yi yığından kaldırın, çıktılayın ve güncelleyin, ardından yığına geri ekleyin:
(A, 2, 2, 4)
(C, 1, 6, 6)
(B, 1, 3, 6)
Bu şekilde devam edersem, istenen karışımı elde ederim. Yığına eşit Öncelikli öğeler eklendiğinde, ilk önce en yüksek Frekans değerine sahip olan (yani en az sıklık) sipariş verilmesini sağlamak için özel bir karşılaştırıcı kullanırım.
Blogumda sorunun ve çözümün daha ayrıntılı bir tanımını yazdım ve onu gösteren bazı çalışma C # kodları sundum. Bkz . Listedeki öğeleri eşit şekilde dağıtma .
Yorumlardan sonra güncelleme
Sorunumun OP'nin sorununa benzer olduğunu ve bu nedenle çözümümün potansiyel olarak yararlı olduğunu düşünüyorum. OP'nin sorusu bağlamında cevabımı daha fazla çerçevelendirmediğim için özür dilerim.
Çözümümün 0, 1 ve 2 yerine A, B ve C kullandığı ilk itiraz kolayca giderildi. Bu sadece bir isimlendirme meselesi. Düşünmek ve "iki 1" den ziyade "iki A" demeyi daha kolay ve daha az kafa karıştırıcı buluyorum. Ancak bu tartışmanın amaçları için OP'nin terminolojisini kullanmak için aşağıdaki çıktıları değiştirdim.
Tabii ki sorunum mesafe kavramıyla ilgileniyor. Eğer "şeyleri eşit şekilde yaymak" istiyorsanız, mesafe belirtilir. Fakat yine de, sorunumun OP'nin sorununa ne kadar benzer olduğunu yeterince gösteremediğim için başarısız oldum.
OP'nin sunduğu iki örnekle birkaç test yaptım. Yani:
[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]
Terminolojimde bunlar sırasıyla [2,2,2] ve [4,3,2,1] olarak ifade edilir. Yani, son örnekte, "0 türünde 4 öğe, 1 türünde 3 öğe, 2 türünde 2 öğe ve 3 türünde 1 öğe."
Test programımı çalıştırdım (hemen aşağıda açıklandığı gibi) ve sonuçlarımı yayınladım. OP'den giriş yapıldığında, sonuçlarımın ona benzer, daha kötü veya daha iyi olup olmadığını söyleyemem. Hiç kimseyi yayınlamadığı için sonuçlarımı kimsenin sonuçlarıyla da karşılaştıramam.
Ben algoritma için iyi bir çözüm sağlar Ancak, diyebiliriz benim sıvının karıştırılması durumunda stratifıkasyonun ortadan kaldırma sorunu. Ve benziyor o OP'ın soruna makul bir çözüm sağlar.
Aşağıda gösterilen sonuçlar için, blog girişimde ayrıntılandırdığım algoritmayı, ilk önceliğe ayarlanmış olarak kullandım Frequency/2
ve yığın karşılaştırıcısı daha sık kullanılan maddeyi tercih etmek için değiştirildi. Değiştirilen kod, değiştirilen satırların yorumuyla birlikte burada gösterilir.
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;
}
}
Test programımı OP'nin ilk örneğiyle çalıştırarak alıyorum:
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
Bu yüzden algoritmam, tüm sayımların eşit olmasının önemsiz problemi için çalışıyor.
OP’nin yayınladığı ikinci sorun için;
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
Bunu geliştirmek için bariz bir yol görmüyorum. Madde 0 [2,3,2,3] veya diğer 2 ve 3 düzenlemeleri için mesafelerin ayarlanması yeniden düzenlenebilir, ancak bu, 1 ve / veya 2 maddelerinin sapmalarını değiştirir. "optimum" bu durumda. Daha sık veya daha az sıklıkta nesneler üzerinde daha büyük bir sapma olması daha mı iyidir?
OP'den başka sorunlardan yoksun olarak, açıklamalarını kendi birkaçımı telafi etmek için kullandım. Görevinde şöyle dedi:
Tipik bir liste, farklı miktarlarda ~ 15 farklı değerde ~ 50 maddeye sahiptir.
Yani iki testim:
[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
Ve sonuçlarım:
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
Ve ikinci örnek için:
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