我試圖生成具有一些限制的半隨機子集。子集的半隨機集
下面是與示例值的變量的描述:
- ObjCount - 對象的數量(12)
- VisibleCount(AKA的setSize) - 每組對象的數量(6)
- SetCount - 組(12)
- ObjAppearances數量 - 在其中出現的對象組的數量=
SetCount * VisibleCount/ObjCount
我需要製作一個給定的多套(SetCount),其遵循以下規則:
- 每一組是對象的集合,但沒有對象可以是在一組不止一次。
- 此外,每個對象應該在相同數量的集合中。 如果它不均勻分佈,那麼一個對象出現的數字集可以被關閉1(一些對象在4個集合中,另外一些在5中)。我會盡量避免這種情況,所以這不是關鍵。
事實證明,這並不像我最初想象的那麼微不足道。任何人都可以幫我一些代碼/ psuedocode?一個通用版本的解決方案也是非常有用的。
在此先感謝。
編輯: VisibleCount是設定的大小。對象出現的次數(ObjAppearances)爲SetCount * VisibleCount/ObjCount
編輯2:我還應該補充說我希望這些集合相當隨機。如果這些集合都具有順序對象(例如set1:5,6,7 set2:3,4,5 set3:10,11,0),則該解決方案無用。對不起,沒有說清楚。
編輯3:這是一個不起作用的解決方案。 (在C#)
static void Main(string[] args)
{
var ObjectCount = 12;
var SetSize = 6;
var SetCount = 12;
var Sets = Enumerable.Range(0, SetCount).Select(i => new List<int>()).ToArray(); // a SetCount-sized array of lists
var ObjectAppearances = SetSize * SetCount/ObjectCount;
var rand = new Random();
// fill the sets
for (int obj = 0; obj < ObjectCount; obj++)
{
for (int a = 0; a < ObjectAppearances; a++)
{
// get the collection of sets that are not full
var nonFullSets = Sets.Where(s => s.Count < SetSize);
// get the collection of non-full sets without obj
var setsWithoutObj = nonFullSets.Where(s => !s.Contains(obj));
///////////////////////
// Here is the problem. All of the non-full sets may already
// have a copy of obj
///////////////////////
// choose a set at random
var currentSetIndex = rand.Next(setsWithoutObj.Count());
var currentSet = setsWithoutObj.ElementAt(currentSetIndex);
// add the object
currentSet.Add(obj);
}
}
// randomize the order within each set and output each
for (int i = 0; i < SetCount; i++)
{
var randomlyOrderedSet = Sets[i].OrderBy(obj => rand.Next());
Sets[i] = new List<int>(randomlyOrderedSet);
// output
foreach (var obj in Sets[i])
Console.Write(string.Format("{0}, ", obj));
Console.WriteLine();
}
Console.ReadLine();
}
這裏的解決方案 - MizardX的答案的實現
static void Main(string[] args)
{
var ObjectCount = 12;
var SetSize = 6;
var SetCount = 10;
var rand = new Random();
// make a matrix [SetCount][ObjectCount]
var Matrix = new int[SetCount][];
for (int s = 0; s < SetCount; s++)
Matrix[s] = Enumerable.Repeat(0, ObjectCount).ToArray();
// put approximately the same number of objects in each set by
// adding sequential objects to sequential sets (not random)
for (int s = 0; s < SetCount; s++)
{
var firstObject = (int)Math.Ceiling((double)s * ObjectCount/SetCount);
for (int i = 0; i < SetSize; i++)
{
var o = (firstObject + i) % ObjectCount;
Matrix[s][o] = 1;
}
}
// output the result
for (int s = 0; s < SetCount; s++)
{
for (int o = 0; o < ObjectCount; o++)
{
Console.Write(string.Format("{0}, ", Matrix[s][o]));
}
Console.WriteLine();
}
Console.WriteLine();
// shuffle sets
Matrix = Matrix.OrderBy(s => rand.Next()).ToArray();
// make a new matrix for shuffle objects
var objOrder = Enumerable.Range(0, ObjectCount).OrderBy(o => rand.Next()).ToArray();
var MatrixSuffled = new int[SetCount][];
for (int s = 0; s < SetCount; s++)
MatrixSuffled[s] = Enumerable.Repeat(0, ObjectCount).ToArray();
for (int o = 0; o < ObjectCount; o++)
{
var oldObj = o;
var newObj = objOrder[o];
for (int s = 0; s < SetCount; s++)
{
MatrixSuffled[s][newObj] = Matrix[s][oldObj];
}
}
// check and output the result
var objectCounters = Enumerable.Repeat(0, ObjectCount).ToArray();
for (int s = 0; s < SetCount; s++)
{
var objectsInThisSet = 0;
for (int o = 0; o < ObjectCount; o++)
{
objectsInThisSet += MatrixSuffled[s][o];
objectCounters[o] += MatrixSuffled[s][o];
Console.Write(string.Format("{0}, ", MatrixSuffled[s][o]));
}
Console.Write(string.Format(" {0}", objectsInThisSet));
Console.WriteLine();
}
// output object count
Console.WriteLine();
for (int o = 0; o < ObjectCount; o++)
Console.Write(string.Format("{0} ", objectCounters[o]));
Console.ReadLine();
}
感謝您的幫助,但請參閱edit2。 – sharoz 2011-02-27 03:51:08
只有你可以在約束條件下獲得很多不同的集合。如果你絕對不想要一個序列,你可以重複這個算法,直到你得到滿意的結果。 – 2011-02-27 04:10:56
我明白了。我會盡力實施並讓你知道很快... – sharoz 2011-02-27 04:33:46