我正在尝试编写一个C#算法,该算法从包含x个元素的池中提供可能的n分区列表。
为了更清楚,我们假设我有一个包含6个元素的池:1,2,3,4,5,6(x = 6) 我应该给3个数字的所有分区,即:
1,2,3 and 4,5,6
1,3,4 and 2,5,6
1,2,5 and 3,4,6
1,2,6 and 3,4,5
etc.
我定位的功能如下:
List<List<List<int>>> GetAllPartitions(int x, int n)
编辑:
我正在寻找的不是组合......对于它,我使用它(取自本网站):
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
return k == 0
? new[] {new T[0]}
: elements.SelectMany((e, i) =>
elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] {e}).Concat(c)));
}
答案 0 :(得分:1)
一般来说,我不做仅链接答案(通常SO也喜欢你展示尝试解决方案),但是有一个完整的代码解决方案,用于任何类型的对象(不仅仅是int)已经用c#编写了:
注意:这将生成集合的每个长度的所有分区,因此您需要在结果列表上进行简单的选择,以仅针对所需的“n”长度分区进行过滤,这可以简单地:
var result = from allResults select result where result.length = n || result.length = x-n
对于担心链接死亡的人,这里是链接代码:
/// <summary>
/// A enumeration of all possible partitions of a set of items.
/// </summary>
/// <typeparam name="T">The type of the items in the set being partitioned.</typeparam>
public sealed class AllPartitionsEnumerable<T> : IEnumerable<IEnumerable<IEnumerable<T>>>
{
/// <summary></summary>
[DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
private IEnumerable<T> items;
/// <summary>
/// Creates and initializes an instance of the <see cref="AllPartitionsEnumerable{T}"/> type.
/// </summary>
/// <param name="items">The set of items to be partitioned.</param>
public AllPartitionsEnumerable(IEnumerable<T> items)
: base ()
{
this.items = items;
}
/// <summary>
/// Gets an enumerator to iterate over the partitions in this enumeration.
/// </summary>
/// <returns>An instance of <see cref="IEnumerator{T}"/>.</returns>
public IEnumerator<IEnumerable<IEnumerable<T>>> GetEnumerator()
{
return new AllPartitionsEnumerator<T>(this.items);
}
/// <summary>
/// Gets an enumerator to iterate over the partitions in this enumeration.
/// </summary>
/// <returns>An instance of <see cref="IEnumerator{T}"/>.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
/// <summary>
/// An enumerator to iterate over the items in an instance of <see cref="AllPartitionsEnumerable{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the items in the set being partitioned.</typeparam>
public sealed class AllPartitionsEnumerator<T> : IEnumerator<IEnumerable<IEnumerable<T>>>
{
/// <summary>The original set of items over which partitions are created.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private T[] items;
/// <summary>Flag to indicate if this enumerator has been disposed of.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool isDisposed;
/// <summary>Flag to indicate if this enumerator is in its initial state.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool isFirst;
/// <summary>The number of partitions in the current selection.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int nc;
/// <summary>An array of values indicating the number of values in the partition at the specified index.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int[] p;
/// <summary>An array of indices indicating to which partition the item at the specified index belongs.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int[] q;
/// <summary>The current partition.</summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private T[][] current;
/// <summary>
/// Creates and initializes an instance of the <see cref="AllPartitionsEnumerator{T}"/> type.
/// </summary>
/// <param name="items">The original set of items over which partitions are enumerated.</param>
public AllPartitionsEnumerator(IEnumerable<T> items)
: base()
{
if (null == items)
{
throw new ArgumentNullException("items");
}
this.isFirst = true;
this.items = items.ToArray();
this.nc = 0;
this.p = new int[this.items.Length];
this.q = new int[this.items.Length];
this.current = null;
}
/// <summary>
/// Gets the current partition.
/// </summary>
public IEnumerable<IEnumerable<T>> Current
{
get
{
this.CheckIfDisposed();
return this.current;
}
}
/// <summary>
/// Disposes of this enumerator and releases all resources held by it.
/// </summary>
public void Dispose()
{
if (this.isDisposed)
{
return;
}
this.isDisposed = true;
this.items = null;
this.p = null;
this.q = null;
this.nc = 0;
this.current = null;
this.isFirst = true;
}
/// <summary>
/// Gets the current partition.
/// </summary>
object IEnumerator.Current
{
get
{
return this.Current;
}
}
/// <summary>
/// Selects the next item in the set of all partitions.
/// </summary>
/// <returns><c>true</c> if an item was selected; <c>false</c> if we are past the last element.</returns>
public bool MoveNext()
{
this.CheckIfDisposed();
if (this.isFirst)
{
this.isFirst = false;
this.nc = 1;
this.p[0] = this.items.Length;
for (int i = 0; i < this.items.Length; ++i)
{
this.q[i] = this.nc;
}
this.Select();
return true;
}
if (this.nc == this.items.Length )
{
return false;
}
int n = this.items.Length;
int m = n;
int l = this.q[m-1];
while (this.p[l - 1] == 1)
{
this.q[m - 1] = 1;
--m;
l = this.q[m - 1];
}
this.nc += m - n;
this.p[0] = this.p[0] + n - m;
if (l == this.nc)
{
++this.nc;
this.p[this.nc - 1] = 0;
}
this.q[m - 1] = l + 1;
this.p[l - 1] = this.p[l - 1] - 1;
this.p[l] = this.p[l] + 1;
this.Select();
return true;
}
/// <summary>
/// Resets this enumerator to its initial state.
/// </summary>
public void Reset()
{
this.CheckIfDisposed();
this.current = null;
this.isFirst = true;
this.isDisposed = false;
this.p = new int[this.items.Length];
this.q = new int[this.items.Length];
this.nc = 0;
}
/// <summary>
/// Selects the items for the current partition.
/// </summary>
private void Select()
{
this.current = new T[this.nc][];
for (int i = 0; i < this.nc; ++i)
{
int k = 0;
this.current[i] = new T[this.p[i]];
for (int j = 0; j < this.items.Length; ++j)
{
if (this.q[j] == i + 1)
{
this.current[i][k] = this.items[j];
++k;
}
}
}
}
/// <summary>
/// Checks and throws an exception if this enumerator has been disposed.
/// </summary>
private void CheckIfDisposed()
{
if (this.isDisposed)
{
throw new ObjectDisposedException(this.GetType().FullName);
}
}
}
/// <summary>
/// Retrieves all possible partitions of a set of items.
/// </summary>
/// <typeparam name="T">The type of the items in the original set.</typeparam>
/// <param name="items">The original set of items over which partitions are created.</param>
/// <returns>All possible partitions of the items in <paramref name="items"/>.</returns>
public static IEnumerable<IEnumerable<IEnumerable<T>>> AllPartitions<T>(this IEnumerable<T> items)
{
return new AllPartitionsEnumerable<T>(items);
}