public static (int, List <int[, ]>) Solve(List <PieceQuantity> pieceQuantities) { var rectangle = SolvingHelper.GenerateRectangle(pieceQuantities); var results = new List <int[, ]>(); int cutLength = 0; int resultsCount = 0; while (true) { var currentPiecesCombinations = GeneratePiecesWithCuts(pieceQuantities, cutLength); foreach (var currentPieces in currentPiecesCombinations) { var currentPiecesCount = currentPieces.Sum(x => x.Quantity); var tempMatrix = new List <int[]>(); var repeatedRowsDictionary = new Dictionary <int, int>(); int pieceIndex = 0, repeatedRowIndex = 0, disctinctRowIndex = 0; foreach (var pieceQuantity in currentPieces) { int rowsCount = 0; for (int i = 0; i < pieceQuantity.Quantity; i++) { var rows = SolvingHelper.CreateRows(pieceQuantity.Piece, rectangle, currentPiecesCount, pieceIndex++); rowsCount = rows.Count; foreach (var row in rows) { repeatedRowsDictionary[repeatedRowIndex++] = disctinctRowIndex++; tempMatrix.Add(row); } disctinctRowIndex -= rowsCount; } disctinctRowIndex += rowsCount; } var matrix = SolvingHelper.ConvertToArray(tempMatrix); if (matrix == null) { continue; } var dlx = new Dlx(); var solutions = dlx.Solve(matrix).ToList(); var distinctSolutionsHashSet = new HashSet <IEnumerable <int> >(new SequenceComparer <int>()); foreach (var solution in solutions) { if (!distinctSolutionsHashSet.Add(solution.RowIndexes.Select(x => repeatedRowsDictionary[x]).OrderBy(x => x))) { continue; } var pieceNumber = 1; foreach (var rowIndex in solution.RowIndexes) { for (int i = currentPiecesCount; i < matrix.GetLength(1); i++) { if (matrix[rowIndex, i] == 1) { rectangle[(i - currentPiecesCount) / rectangle.GetLength(1), (i - currentPiecesCount) % rectangle.GetLength(1)] = pieceNumber; } } pieceNumber++; } results.Add((int[, ])rectangle.Clone()); } var solutionRepetitions = currentPieces .Select(x => Factorial(x.Quantity)) .Aggregate((x, y) => x * y); if (distinctSolutionsHashSet.Count != solutions.Count / solutionRepetitions) { throw new InvalidOperationException("Internal error. Number of distinct solutions is not proper."); } resultsCount += solutions.Count / solutionRepetitions; } if (resultsCount > 0) { return(cutLength, results); } cutLength++; } }
public static (int, int[, ]) Solve(List <PieceQuantity> pieceQuantities) { cancellationTokenSource = new CancellationTokenSource(); bestSolutionIndexes = new List <int>(); currentIteration = 0; maxIteration = 0; var piecesCount = pieceQuantities.Sum(x => x.Quantity); var rectangle = SolvingHelper.GenerateRectangle(pieceQuantities); maxIteration = (ulong)Math.Round(Math.Pow(pieceQuantities.Sum(x => x.Piece.Orientations.Length * x.Quantity), 3)); var tempMatrix = new List <int[]>(); for (int i = 0, j = 0; i < pieceQuantities.Count; i++) { for (int k = 0; k < pieceQuantities[i].Quantity; j++, k++) { tempMatrix.AddRange(SolvingHelper.CreateRows(pieceQuantities[i].Piece, rectangle, piecesCount, j)); } } var matrix = SolvingHelper.ConvertToArray(tempMatrix); if (matrix == null) { return(0, null); } var dlx = new Dlx(cancellationTokenSource.Token); dlx.SolutionFound += DlxSolutionFound; dlx.SearchStep += DlxSearchStep; dlx.Solve(matrix).ToList(); List <IPiece> pieces = pieceQuantities .SelectMany(x => { var list = new List <IPiece>(); for (int i = 0; i < x.Quantity; i++) { list.Add(x.Piece); } return(list); }) .Cast <IPiece>() .ToList(); var pieceNumber = 1; foreach (var index in bestSolutionIndexes) { for (int i = 0; i < piecesCount; i++) { if (matrix[index, i] == 1) { if (!pieces.Remove(GetPiece(pieceQuantities, i))) { throw new InvalidOperationException("Internal error. Could not find piece to remove."); } break; } } for (int i = piecesCount; i < matrix.GetLength(1); i++) { if (matrix[index, i] == 1) { rectangle[(i - piecesCount) / rectangle.GetLength(1), (i - piecesCount) % rectangle.GetLength(1)] = pieceNumber; } } pieceNumber++; } var cutLength = 0; for (int row = 0; row < rectangle.GetLength(0); row++) { for (int column = 0; column < rectangle.GetLength(1); column++) { if (rectangle[row, column] == 0) { cutLength += PutBestPiece(pieces, rectangle, row, column, pieceNumber); pieceNumber++; } } } return(cutLength, rectangle); }