/// <summary>Add a row to the table.</summary> /// <param name="values">the columns that are satisfied by this row</param> public virtual void AddRow(bool[] values) { DancingLinks.Node <ColumnName> prev = null; for (int i = 0; i < values.Length; ++i) { if (values[i]) { DancingLinks.ColumnHeader <ColumnName> top = columns[i]; top.size += 1; DancingLinks.Node <ColumnName> bottom = top.up; DancingLinks.Node <ColumnName> node = new DancingLinks.Node <ColumnName>(null, null , bottom, top, top); bottom.down = node; top.up = node; if (prev != null) { DancingLinks.Node <ColumnName> front = prev.right; node.left = prev; node.right = front; prev.right = node; front.left = node; } else { node.left = node; node.right = node; } prev = node; } } }
/// <summary>Make one move from a prefix</summary> /// <param name="goalRow">the row that should be choosen</param> /// <returns>the row that was found</returns> private DancingLinks.Node <ColumnName> Advance(int goalRow) { DancingLinks.ColumnHeader <ColumnName> col = FindBestColumn(); if (col.size > 0) { CoverColumn(col); DancingLinks.Node <ColumnName> row = col.down; int id = 0; while (row != col) { if (id == goalRow) { DancingLinks.Node <ColumnName> node = row.right; while (node != row) { CoverColumn(node.head); node = node.right; } return(row); } id += 1; row = row.down; } } return(null); }
public DancingLinks() { head = new DancingLinks.ColumnHeader <ColumnName>(null, 0); head.left = head; head.right = head; head.up = head; head.down = head; columns = new AList <DancingLinks.ColumnHeader <ColumnName> >(200); }
internal Node(DancingLinks.Node <ColumnName> l, DancingLinks.Node <ColumnName> r, DancingLinks.Node <ColumnName> u, DancingLinks.Node <ColumnName> d, DancingLinks.ColumnHeader <ColumnName > h) { left = l; right = r; up = u; down = d; head = h; }
/// <summary>Find a solution to the problem.</summary> /// <param name="partial"> /// a temporary datastructure to keep the current partial /// answer in /// </param> /// <param name="output">the acceptor for the results that are found</param> /// <returns>the number of solutions found</returns> private int Search(IList <DancingLinks.Node <ColumnName> > partial, DancingLinks.SolutionAcceptor <ColumnName> output) { int results = 0; if (head.right == head) { IList <IList <ColumnName> > result = new AList <IList <ColumnName> >(partial.Count); foreach (DancingLinks.Node <ColumnName> row in partial) { result.AddItem(GetRowName(row)); } output.Solution(result); results += 1; } else { DancingLinks.ColumnHeader <ColumnName> col = FindBestColumn(); if (col.size > 0) { CoverColumn(col); DancingLinks.Node <ColumnName> row = col.down; while (row != col) { partial.AddItem(row); DancingLinks.Node <ColumnName> node = row.right; while (node != row) { CoverColumn(node.head); node = node.right; } results += Search(partial, output); partial.Remove(partial.Count - 1); node = row.left; while (node != row) { UncoverColumn(node.head); node = node.left; } row = row.down; } UncoverColumn(col); } } return(results); }
/// <summary>Find the column with the fewest choices.</summary> /// <returns>The column header</returns> private DancingLinks.ColumnHeader <ColumnName> FindBestColumn() { int lowSize = int.MaxValue; DancingLinks.ColumnHeader <ColumnName> result = null; DancingLinks.ColumnHeader <ColumnName> current = (DancingLinks.ColumnHeader <ColumnName >)head.right; while (current != head) { if (current.size < lowSize) { lowSize = current.size; result = current; } current = (DancingLinks.ColumnHeader <ColumnName>)current.right; } return(result); }
/// <summary>Uncover a column that was hidden.</summary> /// <param name="col">the column to unhide</param> private void UncoverColumn(DancingLinks.ColumnHeader <ColumnName> col) { Log.Debug("uncover " + col.head.name); DancingLinks.Node <ColumnName> row = col.up; while (row != col) { DancingLinks.Node <ColumnName> node = row.left; while (node != row) { node.head.size += 1; node.down.up = node; node.up.down = node; node = node.left; } row = row.up; } col.right.left = col; col.left.right = col; }
/// <summary>Hide a column in the table</summary> /// <param name="col">the column to hide</param> private void CoverColumn(DancingLinks.ColumnHeader <ColumnName> col) { Log.Debug("cover " + col.head.name); // remove the column col.right.left = col.left; col.left.right = col.right; DancingLinks.Node <ColumnName> row = col.down; while (row != col) { DancingLinks.Node <ColumnName> node = row.right; while (node != row) { node.down.up = node.up; node.up.down = node.down; node.head.size -= 1; node = node.right; } row = row.down; } }
/// <summary>Add a column to the table</summary> /// <param name="name"> /// The name of the column, which will be returned as part of /// solutions /// </param> /// <param name="primary">Is the column required for a solution?</param> public virtual void AddColumn(ColumnName name, bool primary) { DancingLinks.ColumnHeader <ColumnName> top = new DancingLinks.ColumnHeader <ColumnName >(name, 0); top.up = top; top.down = top; if (primary) { DancingLinks.Node <ColumnName> tail = head.left; tail.right = top; top.left = tail; top.right = head; head.left = top; } else { top.left = top; top.right = top; } columns.AddItem(top); }
/// <summary>Generate a list of prefixes down to a given depth.</summary> /// <remarks> /// Generate a list of prefixes down to a given depth. Assumes that the /// problem is always deeper than depth. /// </remarks> /// <param name="depth">the depth to explore down</param> /// <param name="choices">an array of length depth to describe a prefix</param> /// <param name="prefixes">a working datastructure</param> private void SearchPrefixes(int depth, int[] choices, IList <int[]> prefixes) { if (depth == 0) { prefixes.AddItem(choices.MemberwiseClone()); } else { DancingLinks.ColumnHeader <ColumnName> col = FindBestColumn(); if (col.size > 0) { CoverColumn(col); DancingLinks.Node <ColumnName> row = col.down; int rowId = 0; while (row != col) { DancingLinks.Node <ColumnName> node = row.right; while (node != row) { CoverColumn(node.head); node = node.right; } choices[choices.Length - depth] = rowId; SearchPrefixes(depth - 1, choices, prefixes); node = row.left; while (node != row) { UncoverColumn(node.head); node = node.left; } row = row.down; rowId += 1; } UncoverColumn(col); } } }