using System; using System.Collections.Generic; using System.Linq; public class Skyscrapers { private static IEnumerable> Permutations(List initial) where T: IComparable { yield return initial; var hasNext = initial.Count > 1; while (hasNext) { var k = 0; var l = 0; hasNext = false; for (var i = initial.Count - 1; i > 0; i--) { if (initial[i].CompareTo(initial[i - 1]) > 0) { k = i - 1; hasNext = true; break; } } for (var i = initial.Count - 1; i > k; i--) { if (initial[i].CompareTo(initial[k]) > 0) { l = i; break; } } (initial[k], initial[l]) = (initial[l], initial[k]); initial.Reverse(k + 1, initial.Count - k - 1); if (hasNext) { yield return initial; } } } private static bool IsValid(List heights, int clue) { var canSee = 1; var lastHeight = heights[0]; for (var i = 1; i < heights.Count; i++) { var currentHeight = heights[i]; if (currentHeight > lastHeight) { lastHeight = currentHeight; canSee++; } } return canSee == clue; } private static IEnumerable> PossibleHeights(int size, int clue) { var initial = new List(); for (var i = 0; i < size; i++) { initial.Add(i + 1); } if (clue == 0) { return Permutations(initial); } return Permutations(initial).Where(heights => IsValid(heights, clue)); } private static int Size { get => 4; } private static (int, int) GetDiffs(int clueIndex) { if (clueIndex < Size) { return (0, 1); } else if (clueIndex < 2 * Size) { return (-1, 0); } else if (clueIndex < 3 * Size) { return (0, -1); } return (1, 0); } private static (int, int) GetStarts(int clueIndex) { if (clueIndex < Size) { return (clueIndex, 0); } else if (clueIndex < 2 * Size) { return (Size - 1, clueIndex % Size); } else if (clueIndex < 3 * Size) { return (Size - 1 - clueIndex % Size, Size - 1); } return (0, Size - 1 - clueIndex % Size); } private static List BackupHeights(int[][] heights, int clueIndex) { var backup = new List(); var (dx, dy) = GetDiffs(clueIndex); for ( var (x, y) = GetStarts(clueIndex); x >= 0 && x < Size && y >= 0 && y < Size; x += dx, y += dy ) { backup.Add(heights[y][x]); } return backup; } private static bool EmplaceHeights( int[][] heights, int clueIndex, List newHeights, bool force ) { int i = 0; var (dx, dy) = GetDiffs(clueIndex); for ( var (x, y) = GetStarts(clueIndex); x >= 0 && x < Size && y >= 0 && y < Size; x += dx, y += dy ) { if ( !force && heights[y][x] != 0 && heights[y][x] != newHeights[i] ) { return false; } heights[y][x] = newHeights[i++]; } return true; } private static bool SolvePuzzle( int[][] heights, int[] clues, int clueIndex, bool ignoreZeroes ) { while (clueIndex < 4 * Size && ( (ignoreZeroes && clues[clueIndex] == 0) || (!ignoreZeroes && clues[clueIndex] != 0) )) { clueIndex++; } if (clueIndex >= 4 * Size) { return true; } // create copy of heights to ensure correct resetting var currentHeights = BackupHeights(heights, clueIndex); // iterate through the options foreach (var possibleHeights in PossibleHeights(Size, clues[clueIndex])) { // emplace heights and if conflict occurs, reset and try next one if (!EmplaceHeights(heights, clueIndex, possibleHeights, false)) { EmplaceHeights(heights, clueIndex, currentHeights, true); continue; } // if no conflict present, try filling out other clues if (SolvePuzzle(heights, clues, clueIndex + 1, ignoreZeroes)) { return true; } // otherwise reset heights and try again EmplaceHeights(heights, clueIndex, currentHeights, true); } // if we got here, there is no feasible configuration of buildings return false; } public static int[][] SolvePuzzle(int[] clues) { var result = new int[Size][]; for (var i = 0; i < Size; i++) { result[i] = new int[Size]; } SolvePuzzle(result, clues, 0, true); // in case there are left zeroes SolvePuzzle(result, clues, 0, false); return result; } }