I am having a general problem finding a good algorithm for generating each possible assignment for some integers in different arrays.
Lets say I have n arrays and m
The following code is written in C#.
class LineList : List
{
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(Count).AppendLine(" lines:");
foreach (var line in this)
{
if (line.Length > 0)
{
foreach (var bucket in line)
{
sb.Append('{');
foreach (var item in bucket)
{
sb.Append(item).Append(',');
}
if (bucket.Length > 0)
{
sb.Length -= 1;
}
sb.Append("}, ");
}
sb.Length -= 2;
}
sb.AppendLine();
}
return sb.ToString();
}
}
class Permutor
{
public T[] Items { get; private set; }
public bool ReuseBuckets { get; set; }
private T[] emptyBucket_;
private Dictionary> buckets_; // for memoization when ReuseBuckets=true
public Permutor(T[] items)
{
ReuseBuckets = true; // faster and uses less memory
Items = items;
emptyBucket_ = new T[0];
buckets_ = new Dictionary>();
}
private T[] GetBucket(int index, int size)
{
if (size == 0)
{
return emptyBucket_;
}
Dictionary forIndex;
if (!buckets_.TryGetValue(index, out forIndex))
{
forIndex = new Dictionary();
buckets_[index] = forIndex;
}
T[] bucket;
if (!forIndex.TryGetValue(size, out bucket))
{
bucket = new T[size];
Array.Copy(Items, index, bucket, 0, size);
forIndex[size] = bucket;
}
return bucket;
}
public LineList GetLines(int bucketsPerLine)
{
var lines = new LineList();
if (bucketsPerLine > 0)
{
AddLines(lines, bucketsPerLine, 0);
}
return lines;
}
private void AddLines(LineList lines, int bucketAllotment, int taken)
{
var start = bucketAllotment == 1 ? Items.Length - taken : 0;
var stop = Items.Length - taken;
for (int nItemsInNextBucket = start; nItemsInNextBucket <= stop; nItemsInNextBucket++)
{
T[] nextBucket;
if (ReuseBuckets)
{
nextBucket = GetBucket(taken, nItemsInNextBucket);
}
else
{
nextBucket = new T[nItemsInNextBucket];
Array.Copy(Items, taken, nextBucket, 0, nItemsInNextBucket);
}
if (bucketAllotment > 1)
{
var subLines = new LineList();
AddLines(subLines, bucketAllotment - 1, taken + nItemsInNextBucket);
foreach (var subLine in subLines)
{
var line = new T[bucketAllotment][];
line[0] = nextBucket;
subLine.CopyTo(line, 1);
lines.Add(line);
}
}
else
{
var line = new T[1][];
line[0] = nextBucket;
lines.Add(line);
}
}
}
}
These calls...
var permutor = new Permutor(new[] { 1, 2, 3 });
for (int bucketsPerLine = 0; bucketsPerLine <= 4; bucketsPerLine++)
{
Console.WriteLine(permutor.GetLines(bucketsPerLine));
}
generate this output...
0 lines:
1 lines:
{1,2,3}
4 lines:
{}, {1,2,3}
{1}, {2,3}
{1,2}, {3}
{1,2,3}, {}
10 lines:
{}, {}, {1,2,3}
{}, {1}, {2,3}
{}, {1,2}, {3}
{}, {1,2,3}, {}
{1}, {}, {2,3}
{1}, {2}, {3}
{1}, {2,3}, {}
{1,2}, {}, {3}
{1,2}, {3}, {}
{1,2,3}, {}, {}
20 lines:
{}, {}, {}, {1,2,3}
{}, {}, {1}, {2,3}
{}, {}, {1,2}, {3}
{}, {}, {1,2,3}, {}
{}, {1}, {}, {2,3}
{}, {1}, {2}, {3}
{}, {1}, {2,3}, {}
{}, {1,2}, {}, {3}
{}, {1,2}, {3}, {}
{}, {1,2,3}, {}, {}
{1}, {}, {}, {2,3}
{1}, {}, {2}, {3}
{1}, {}, {2,3}, {}
{1}, {2}, {}, {3}
{1}, {2}, {3}, {}
{1}, {2,3}, {}, {}
{1,2}, {}, {}, {3}
{1,2}, {}, {3}, {}
{1,2}, {3}, {}, {}
{1,2,3}, {}, {}, {}
The approximate size of the solution (bucketsPerLine * NumberOfLines) dominates the execution time. For these tests, N is the length of the input array and the bucketsPerLine is set to N as well.
N=10, solutionSize=923780, elapsedSec=0.4, solutionSize/elapsedMS=2286
N=11, solutionSize=3879876, elapsedSec=2.1, solutionSize/elapsedMS=1835
N=12, solutionSize=16224936, elapsedSec=10.0, solutionSize/elapsedMS=1627
N=13, solutionSize=67603900, elapsedSec=47.9, solutionSize/elapsedMS=1411