Saya menemukan pertanyaan ini sambil meneliti masalah serupa: penambahan cairan yang optimal untuk mengurangi stratifikasi. Sepertinya solusi saya akan berlaku untuk situasi Anda, juga.
Jika Anda ingin mencampur cairan A, B, dan C dalam proporsi 30,20,10 (yaitu, 30 unit A, 20 unit B, dan 10 unit C), Anda berakhir dengan stratifikasi jika Anda menambahkan semua A, lalu semua B, dan semua C. Anda lebih baik mencampur unit yang lebih kecil. Misalnya, lakukan penambahan unit tunggal dalam urutan [A, B, A, C, B, A]. Itu akan mencegah stratifikasi sama sekali.
Cara yang saya temukan untuk melakukannya adalah memperlakukannya sebagai semacam penggabungan, menggunakan antrian prioritas. Jika saya membuat struktur untuk menjelaskan penambahan:
MergeItem
Item, Count, Frequency, Priority
Frekuensi dinyatakan sebagai "satu setiap N". Jadi A, yang ditambahkan tiga dari enam kali, memiliki frekuensi 2 (6/3).
Dan inisialisasi heap yang awalnya berisi:
(A, 3, 2, 2)
(B, 2, 3, 3)
(C, 1, 6, 6)
Sekarang, saya menghapus item pertama dari heap dan mengeluarkannya. Kemudian kurangi hitungannya dengan 1 dan tambah Prioritas dengan Frekuensi dan tambahkan kembali ke heap. Tumpukan yang dihasilkan adalah:
(B, 2, 3, 0)
(A, 2, 2, 4)
(C, 1, 6, 6)
Selanjutnya, hapus B dari heap, output dan perbarui, lalu tambahkan kembali ke heap:
(A, 2, 2, 4)
(C, 1, 6, 6)
(B, 1, 3, 6)
Jika saya melanjutkan dengan cara itu, saya mendapatkan campuran yang diinginkan. Saya menggunakan pembanding khusus untuk memastikan bahwa ketika item Prioritas yang sama dimasukkan ke dalam tumpukan, item dengan nilai Frekuensi tertinggi (yaitu yang paling jarang) dipesan terlebih dahulu.
Saya menulis deskripsi yang lebih lengkap tentang masalah dan solusinya di blog saya, dan menyajikan beberapa kode C # yang menggambarkannya. Lihat Mendistribusikan item secara merata dalam daftar .
Perbarui setelah komentar
Saya pikir masalah saya mirip dengan masalah OP, dan karena itu solusi saya berpotensi berguna. Saya minta maaf karena tidak membingkai jawaban saya lebih lanjut dalam hal pertanyaan OP.
Keberatan pertama, bahwa solusi saya menggunakan A, B, dan C daripada 0, 1, dan 2, mudah diatasi. Ini hanya masalah nomenklatur. Saya merasa lebih mudah dan kurang membingungkan untuk memikirkan dan mengatakan "dua A" daripada "dua 1". Tetapi untuk tujuan diskusi ini saya telah memodifikasi hasil saya di bawah ini untuk menggunakan nomenklatur OP.
Tentu saja masalah saya berkaitan dengan konsep jarak. Jika Anda ingin "menyebar semuanya secara merata," jarak tersirat. Tapi, sekali lagi, itu adalah kegagalan saya karena tidak cukup menunjukkan bagaimana masalah saya mirip dengan masalah OP.
Saya menjalankan beberapa tes dengan dua contoh yang diberikan OP. Itu adalah:
[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]
Dalam nomenklatur saya, masing-masing dinyatakan sebagai [2,2,2] dan [4,3,2,1]. Yaitu, dalam contoh terakhir, "4 item tipe 0, 3 item tipe 1, 2 item tipe 2, dan 1 item tipe 3."
Saya menjalankan program pengujian saya (seperti yang dijelaskan langsung di bawah), dan telah memposting hasil saya. Tanpa masukan dari OP, saya tidak bisa mengatakan apakah hasil saya mirip, lebih buruk daripada, atau lebih baik dari itu. Saya juga tidak dapat membandingkan hasil saya dengan hasil orang lain karena tidak ada orang lain yang memposting.
Saya dapat mengatakan, bagaimanapun, bahwa algoritma menyediakan solusi yang baik untuk masalah saya menghilangkan stratifikasi ketika mencampur cairan. Dan sepertinya itu memberikan solusi yang masuk akal untuk masalah OP.
Untuk hasil yang ditunjukkan di bawah ini, saya menggunakan algoritma yang saya perinci dalam entri blog saya, dengan prioritas awal yang ditetapkan Frequency/2
, dan pembanding tumpukan diubah untuk mendukung item yang lebih sering. Kode yang dimodifikasi ditampilkan di sini, dengan garis yang dimodifikasi dikomentari.
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;
}
}
Menjalankan program pengujian saya dengan contoh pertama OP, saya mendapatkan:
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
Jadi algoritma saya bekerja untuk masalah sepele dari semua yang dianggap sama.
Untuk masalah kedua yang diposting OP, saya dapat:
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
Saya tidak melihat cara yang jelas untuk memperbaiki itu. Bisa diatur ulang untuk membuat jarak untuk item 0 [2,3,2,3] atau pengaturan 2 dan 3 lainnya, tetapi itu akan mengubah penyimpangan untuk item 1 dan / atau 2. Saya benar-benar tidak tahu apa "optimal" ada dalam situasi ini. Apakah lebih baik untuk memiliki penyimpangan yang lebih besar pada item yang lebih sering atau lebih jarang?
Karena tidak memiliki masalah lain dari OP, saya menggunakan deskripsinya untuk mengatasinya sendiri. Dia mengatakan dalam posnya:
Daftar tipikal memiliki ~ 50 item dengan ~ 15 nilai berbeda dalam jumlah bervariasi.
Jadi dua tes saya adalah:
[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
Dan hasil saya:
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
Dan untuk contoh kedua:
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