├── 1.Очереди, стеки, дженерики ├── CloneVersionSystem.cs └── Monobilliards.cs ├── 10.Структуры данных ├── BinaryTree.cs └── DiskTreeTask.cs ├── 2.yield return ├── ExpSmoothingTask.cs ├── MovingAverageTask.cs └── MovingMaxTask.cs ├── 3.Листы и словари └── GhostsTask.cs ├── 4.Делегаты ├── BrainfuckBasicCommands.cs ├── BrainfuckLoopCommands.cs └── VirtualMachine.cs ├── 5.Функциональное программирование ├── ControlTask.cs ├── ForcesTask.cs └── LevelsTask.cs ├── 6.LINQ ├── ExtensionsTask.cs ├── ParsingTask.cs └── StatisticsTask.cs ├── 7.Графы и обходы ├── BfsTask.cs ├── DungeonTask.cs └── RivalsTask.cs ├── 8.Жадные алгоритмы ├── GreedyPathFinder.cs └── NotGreedyPathFinder.cs ├── 9.Динамическое программирование ├── FlagsTask.cs └── TicketsTask.cs └── README.md /1.Очереди, стеки, дженерики/CloneVersionSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Clones 4 | { 5 | public class CloneVersionSystem : ICloneVersionSystem 6 | { 7 | private readonly List cloneList; 8 | 9 | public CloneVersionSystem() 10 | { 11 | cloneList = new List { new Clone() }; 12 | } 13 | 14 | public string Execute(string query) 15 | { 16 | var queryArr = query.Split(' '); 17 | var cloneNum = int.Parse(queryArr[1]) - 1; 18 | 19 | switch (queryArr[0]) 20 | { 21 | case "check": 22 | return cloneList[cloneNum].Check(); 23 | 24 | case "learn": 25 | var programNum = int.Parse(queryArr[2]); 26 | cloneList[cloneNum].Learn(programNum); 27 | return null; 28 | 29 | case "rollback": 30 | cloneList[cloneNum].RollBack(); 31 | return null; 32 | 33 | case "relearn": 34 | cloneList[cloneNum].Relearn(); 35 | return null; 36 | 37 | case "clone": 38 | cloneList.Add(new Clone(cloneList[cloneNum])); 39 | return null; 40 | } 41 | return null; 42 | } 43 | } 44 | 45 | public class Clone 46 | { 47 | private readonly Stack learnedProgramms; 48 | private readonly Stack rollBackHistory; 49 | 50 | public Clone() 51 | { 52 | learnedProgramms = new Stack(); 53 | rollBackHistory = new Stack(); 54 | } 55 | 56 | public Clone(Clone anotherClone) 57 | { 58 | learnedProgramms = new Stack(anotherClone.learnedProgramms); 59 | rollBackHistory = new Stack(anotherClone.rollBackHistory); 60 | } 61 | 62 | public void Learn(int commandNumber) 63 | { 64 | rollBackHistory.Clear(); 65 | learnedProgramms.Push(commandNumber); 66 | } 67 | 68 | public void RollBack() 69 | { 70 | rollBackHistory.Push(learnedProgramms.Pop()); 71 | } 72 | 73 | public void Relearn() 74 | { 75 | learnedProgramms.Push(rollBackHistory.Pop()); 76 | } 77 | 78 | public string Check() 79 | { 80 | return learnedProgramms.IsEmpty() ? "basic" : learnedProgramms.Peek().ToString(); 81 | } 82 | } 83 | 84 | public class Stack 85 | { 86 | private StackItem last; 87 | public Stack() { } 88 | 89 | public Stack(Stack stack) 90 | { 91 | last = stack.last; 92 | } 93 | 94 | public void Push(int value) 95 | { 96 | last = new StackItem(value, last); 97 | } 98 | 99 | public int Peek() 100 | { 101 | return last.Value; 102 | } 103 | 104 | public int Pop() 105 | { 106 | var value = last.Value; 107 | last = last.Previous; 108 | return value; 109 | } 110 | 111 | public bool IsEmpty() 112 | { 113 | return last == null; 114 | } 115 | 116 | public void Clear() 117 | { 118 | last = null; 119 | } 120 | } 121 | 122 | public class StackItem 123 | { 124 | public readonly int Value; 125 | public readonly StackItem Previous; 126 | 127 | public StackItem(int value, StackItem previous) 128 | { 129 | Value = value; 130 | Previous = previous; 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /1.Очереди, стеки, дженерики/Monobilliards.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла Monobilliards.cs 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections; 5 | using System.Linq; 6 | 7 | namespace Monobilliards 8 | { 9 | public class Monobilliards : IMonobilliards 10 | { 11 | public bool IsCheater(IList inspectedBalls) 12 | { 13 | var stack = new Stack(); 14 | var removedBalls = new HashSet(); 15 | int peek = 0; 16 | 17 | foreach (var ball in inspectedBalls) 18 | { 19 | if (stack.Count == 0) 20 | { 21 | for (int i = 1; i < ball; i++) 22 | stack.Push(i); 23 | } 24 | 25 | else 26 | { 27 | if (ball == stack.First()) stack.Pop(); 28 | 29 | else if (ball > stack.First()) 30 | { 31 | if (peek < stack.First()) peek = stack.First(); 32 | 33 | for (int i = peek + 1; i < ball; i++) 34 | 35 | if (!removedBalls.Contains(i)) stack.Push(i); 36 | else removedBalls.Remove(i); 37 | 38 | peek = ball; 39 | } 40 | else return true; 41 | } 42 | removedBalls.Add(ball); 43 | } 44 | return false; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /10.Структуры данных/BinaryTree.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла BinaryTree.cs 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | namespace BinaryTrees 7 | { 8 | public class BinaryTree : IEnumerable where T : IComparable 9 | { 10 | private TreeNode root; 11 | 12 | public T this[int index] 13 | { 14 | get 15 | { 16 | if (root == null || index < 0 || index >= root.Size) throw new IndexOutOfRangeException(); 17 | var currentNode = root; 18 | while (true) 19 | { 20 | var leftSize = currentNode.Left?.Size ?? 0; 21 | if (index == leftSize) 22 | return currentNode.Value; 23 | if (index < leftSize) 24 | currentNode = currentNode.Left; 25 | else 26 | { 27 | currentNode = currentNode.Right; 28 | index -= 1 + leftSize; 29 | } 30 | } 31 | } 32 | } 33 | 34 | public void Add(T key) 35 | { 36 | var nodeToAdd = new TreeNode(key); 37 | if (root == null) 38 | root = nodeToAdd; 39 | else 40 | { 41 | var currentNode = root; 42 | while (true) 43 | { 44 | if (currentNode.Value.CompareTo(key) > 0) 45 | { 46 | if (currentNode.Left == null) 47 | { 48 | currentNode.Left = new TreeNode(key); 49 | break; 50 | } 51 | currentNode = currentNode.Left; 52 | } 53 | else 54 | { 55 | if (currentNode.Right == null) 56 | { 57 | currentNode.Right = new TreeNode(key); 58 | break; 59 | } 60 | currentNode = currentNode.Right; 61 | } 62 | } 63 | } 64 | } 65 | 66 | public bool Contains(T key) 67 | { 68 | var currentNode = root; 69 | while (currentNode != null) 70 | { 71 | var diff = currentNode.Value.CompareTo(key); 72 | if (diff == 0) 73 | return true; 74 | currentNode = diff > 0 ? currentNode.Left : currentNode.Right; 75 | } 76 | return false; 77 | } 78 | 79 | public IEnumerator GetEnumerator() 80 | { 81 | return root?.GetValues().GetEnumerator(); 82 | } 83 | 84 | IEnumerator IEnumerable.GetEnumerator() 85 | { 86 | return GetEnumerator(); 87 | } 88 | } 89 | 90 | internal class TreeNode where T : IComparable 91 | { 92 | public T Value { get; } 93 | private TreeNode parentNode; 94 | private TreeNode left; 95 | 96 | public TreeNode Left 97 | { 98 | get { return left; } 99 | set 100 | { 101 | if (left != null) 102 | OnChildCountChanged(-left.Size); 103 | left = value; 104 | if (value != null) 105 | { 106 | OnChildCountChanged(value.Size); 107 | value.parentNode = this; 108 | } 109 | } 110 | } 111 | 112 | private TreeNode right; 113 | public TreeNode Right 114 | { 115 | get { return right; } 116 | set 117 | { 118 | if (right != null) 119 | OnChildCountChanged(-right.Size); 120 | right = value; 121 | if (value != null) 122 | { 123 | OnChildCountChanged(value.Size); 124 | value.parentNode = this; 125 | } 126 | } 127 | } 128 | 129 | public int Size { get; private set; } 130 | 131 | public TreeNode(T value) 132 | { 133 | if (value == null) 134 | throw new ArgumentNullException(nameof(value)); 135 | Value = value; 136 | Size = 1; 137 | } 138 | 139 | public IEnumerable GetValues() 140 | { 141 | if (Left != null) 142 | foreach (var value in Left.GetValues()) 143 | yield return value; 144 | yield return Value; 145 | if (Right != null) 146 | foreach (var value in Right.GetValues()) 147 | yield return value; 148 | } 149 | 150 | private void OnChildCountChanged(int delta) 151 | { 152 | Size += delta; 153 | parentNode?.OnChildCountChanged(delta); 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /10.Структуры данных/DiskTreeTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DiskTree 6 | { 7 | public class DiskTreeTask 8 | { 9 | public class Root 10 | { 11 | public string Name; 12 | public Dictionary Nodes = new Dictionary(); 13 | 14 | public Root(string name) 15 | { 16 | Name = name; 17 | } 18 | 19 | public Root GetDirection(string subRoot) 20 | { 21 | return Nodes.TryGetValue(subRoot, out Root node) 22 | ? node : Nodes[subRoot] = new Root(subRoot); 23 | } 24 | 25 | public List MakeConcluson(int i, List list) 26 | { 27 | if (i >= 0) 28 | list.Add(new string(' ', i) + Name); 29 | i++; 30 | 31 | foreach (var child in Nodes.Values.OrderBy(root => root.Name, 32 | StringComparer.Ordinal)) 33 | list = child.MakeConcluson(i, list); 34 | return list; 35 | } 36 | } 37 | 38 | public static List Solve(List input) 39 | { 40 | var root = new Root(""); 41 | foreach (var name in input) 42 | { 43 | var path = name.Split('\\'); 44 | var node = root; 45 | foreach (var item in path) 46 | node = node.GetDirection(item); 47 | } 48 | 49 | return root.MakeConcluson(-1, new List()); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /2.yield return/ExpSmoothingTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла ExpSmoothingTask.cs 2 | using System.Collections.Generic; 3 | 4 | namespace yield 5 | { 6 | public static class ExpSmoothingTask 7 | { 8 | public static IEnumerable SmoothExponentialy(this IEnumerable data, double alpha) 9 | { 10 | var isFirstItem = true; 11 | double previousItem = 0; 12 | foreach (var e in data) 13 | { 14 | var item = new DataPoint(); 15 | item.AvgSmoothedY = e.AvgSmoothedY; 16 | item.MaxY = e.MaxY; 17 | item.OriginalY = e.OriginalY; 18 | item.X = e.X; 19 | if(isFirstItem) 20 | { 21 | isFirstItem = false; 22 | previousItem = e.OriginalY; 23 | } 24 | else 25 | { 26 | previousItem = alpha * e.OriginalY + (1 - alpha) * previousItem; 27 | } 28 | item.ExpSmoothedY = previousItem; 29 | yield return item; 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /2.yield return/MovingAverageTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла MovingAverageTask.cs 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace yield 6 | { 7 | public static class MovingAverageTask 8 | { 9 | public static IEnumerable MovingAverage(this IEnumerable data, int windowWidth) 10 | { 11 | var windowValues = new WindowValues(windowWidth); 12 | var windowsSum = 0.0; 13 | 14 | foreach (var dataPoint in data) 15 | { 16 | var tailY = windowValues.Length == windowWidth ? windowValues.Tail.Value : 0; 17 | windowValues.Append(dataPoint.OriginalY); 18 | windowsSum -= tailY; 19 | windowsSum += dataPoint.OriginalY; 20 | 21 | yield return CreateDataPoint(dataPoint, windowsSum / windowValues.Length); 22 | } 23 | } 24 | 25 | private static DataPoint CreateDataPoint(DataPoint currentDataPoint, double nextSmoothValue) 26 | { 27 | return new DataPoint 28 | { 29 | X = currentDataPoint.X, 30 | AvgSmoothedY = nextSmoothValue, 31 | OriginalY = currentDataPoint.OriginalY 32 | }; 33 | } 34 | } 35 | 36 | internal class WindowValues : IEnumerable 37 | { 38 | private readonly int capacity; 39 | 40 | public WindowValues(int capacity) 41 | { 42 | this.capacity = capacity; 43 | } 44 | 45 | public int Length { get; private set; } 46 | public WindowElement Head { get; private set; } 47 | public WindowElement Tail { get; private set; } 48 | 49 | public IEnumerator GetEnumerator() 50 | { 51 | return new WindowElementEnumerator(this); 52 | } 53 | 54 | IEnumerator IEnumerable.GetEnumerator() 55 | { 56 | return GetEnumerator(); 57 | } 58 | 59 | public void Append(T value) 60 | { 61 | if (Head == null) 62 | { 63 | Head = new WindowElement {Value = value, Next = null}; 64 | Tail = Head; 65 | Length++; 66 | return; 67 | } 68 | 69 | Head.Next = new WindowElement {Value = value, Next = null}; 70 | Head = Head.Next; 71 | if (Length < capacity) 72 | { 73 | Length++; 74 | return; 75 | } 76 | 77 | Tail = Tail.Next; 78 | } 79 | } 80 | 81 | internal class WindowElement 82 | { 83 | public WindowElement Next; 84 | public T Value; 85 | } 86 | 87 | internal class WindowElementEnumerator : IEnumerator 88 | { 89 | private readonly WindowValues window; 90 | private WindowElement currentElement; 91 | 92 | public WindowElementEnumerator(WindowValues window) 93 | { 94 | this.window = window; 95 | currentElement = null; 96 | } 97 | 98 | public void Dispose() 99 | { 100 | } 101 | 102 | public bool MoveNext() 103 | { 104 | currentElement = currentElement == null ? window.Tail : currentElement.Next; 105 | return currentElement != null; 106 | } 107 | 108 | public void Reset() 109 | { 110 | } 111 | 112 | public T Current => currentElement.Value; 113 | 114 | object IEnumerator.Current => Current; 115 | } 116 | } -------------------------------------------------------------------------------- /2.yield return/MovingMaxTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | 5 | namespace yield 6 | { 7 | public static class MovingMaxTask 8 | { 9 | public static IEnumerable MovingMax(this IEnumerable data, int windowWidth) 10 | { 11 | var points = new LinkedList(); 12 | var pointsX = new Queue(); 13 | foreach (var point in data) 14 | { 15 | pointsX.Enqueue(point.X); 16 | if (pointsX.Count > windowWidth && points.First.Value <= pointsX.Dequeue()) 17 | { 18 | points.RemoveFirst(); 19 | points.RemoveFirst(); 20 | } 21 | while (points.Count != 0 && points.Last.Value < point.OriginalY) 22 | { 23 | points.RemoveLast(); 24 | points.RemoveLast(); 25 | } 26 | points.AddLast(point.X); 27 | points.AddLast(point.OriginalY); 28 | point.MaxY = points.First.Next.Value; 29 | yield return point; 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /3.Листы и словари/GhostsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла GhostsTask.cs 2 | using System; 3 | using System.Runtime.CompilerServices; 4 | using System.Text; 5 | 6 | namespace hashes 7 | { 8 | public class GhostsTask : 9 | IFactory, IFactory, IFactory, IFactory, IFactory, 10 | IMagic 11 | { 12 | private byte[] documentArray = { 1, 1, 2 }; 13 | Document document; 14 | Segment segment; 15 | Cat cat = new Cat("Tikhon", "Attic basement", DateTime.MaxValue); 16 | Vector vector = new Vector(0, 0); 17 | Robot robot = new Robot("C-3PO"); 18 | 19 | public GhostsTask() 20 | { 21 | segment = new Segment(vector, vector); 22 | document = new Document("Russian Hackers", Encoding.Unicode, documentArray); 23 | } 24 | 25 | public void DoMagic() 26 | { 27 | documentArray[0] = 10; 28 | vector.Add(new Vector(2, 28)); 29 | cat.Rename("Tisha"); 30 | Robot.BatteryCapacity++; 31 | } 32 | 33 | Document IFactory.Create() 34 | { 35 | return document; 36 | } 37 | 38 | Vector IFactory.Create() 39 | { 40 | return vector; 41 | } 42 | 43 | Segment IFactory.Create() 44 | { 45 | return segment; 46 | } 47 | 48 | Cat IFactory.Create() 49 | { 50 | return cat; 51 | } 52 | 53 | Robot IFactory.Create() 54 | { 55 | return robot; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /4.Делегаты/BrainfuckBasicCommands.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла BrainfuckBasicCommands.cs 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace func.brainfuck 7 | { 8 | public class Constant 9 | { 10 | static readonly char[] constant = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890".ToCharArray(); 11 | 12 | public static void Constants(IVirtualMachine vm) 13 | { 14 | foreach (var chars in constant) 15 | { 16 | vm.RegisterCommand(chars, machine => machine.Memory[machine.MemoryPointer] = (byte)chars); 17 | } 18 | } 19 | } 20 | 21 | public class BrainfuckBasicCommands 22 | { 23 | public static void RightOrLeftByteShift(IVirtualMachine vm) 24 | { 25 | vm.RegisterCommand('<', machine => 26 | { 27 | machine.MemoryPointer = Calc(machine.MemoryPointer, -1, machine.Memory.Length); 28 | }); 29 | 30 | vm.RegisterCommand('>', machine => 31 | { 32 | machine.MemoryPointer = Calc(machine.MemoryPointer, 1, machine.Memory.Length); 33 | }); 34 | } 35 | 36 | public static void IncOrDecByte(IVirtualMachine vm) 37 | { 38 | vm.RegisterCommand('+', machine => 39 | { 40 | var bytes = machine.Memory[machine.MemoryPointer]; 41 | var length = machine.Memory.Length; 42 | 43 | machine.Memory[machine.MemoryPointer] = bytes == 255 44 | ? machine.Memory[machine.MemoryPointer] = 0 45 | : (byte)Calc(bytes, 1, length); 46 | }); 47 | 48 | vm.RegisterCommand('-', machine => 49 | { 50 | var bytes = machine.Memory[machine.MemoryPointer]; 51 | var length = machine.Memory.Length; 52 | 53 | machine.Memory[machine.MemoryPointer] = bytes == 0 54 | ? machine.Memory[machine.MemoryPointer] = 255 55 | : (byte)Calc(bytes, -1, length); 56 | }); 57 | } 58 | 59 | public static int Calc(int a, int b, int modulus) 60 | { 61 | return (a + modulus + b % modulus) % modulus; 62 | } 63 | 64 | public static void RegisterTo(IVirtualMachine vm, Func read, Action write) 65 | { 66 | Constant.Constants(vm); 67 | 68 | RightOrLeftByteShift(vm); 69 | 70 | IncOrDecByte(vm); 71 | 72 | vm.RegisterCommand('.', machine => write((char)machine.Memory[machine.MemoryPointer])); 73 | 74 | vm.RegisterCommand(',', machine => machine.Memory[machine.MemoryPointer] = (byte) read()); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /4.Делегаты/BrainfuckLoopCommands.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла BrainfuckLoopCommands.cs 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace func.brainfuck 7 | { 8 | public class BrainfuckLoopCommands 9 | { 10 | public static Dictionary Bracket = new Dictionary(); 11 | public static Dictionary ClosingBracket = new Dictionary(); 12 | public static Stack Stack = new Stack(); 13 | 14 | public static void BodyLoop(IVirtualMachine vm) 15 | { 16 | for (int i = 0; i < vm.Instructions.Length; i++) 17 | { 18 | var bracket = vm.Instructions[i]; 19 | switch (bracket) 20 | { 21 | case '[': 22 | Stack.Push(i); 23 | break; 24 | case ']': 25 | ClosingBracket[i] = Stack.Peek(); 26 | Bracket[Stack.Pop()] = i; 27 | break; 28 | } 29 | } 30 | } 31 | 32 | public static void RegisterTo(IVirtualMachine vm) 33 | { 34 | BodyLoop(vm); 35 | 36 | vm.RegisterCommand('[', machine => 37 | { 38 | if (machine.Memory[machine.MemoryPointer] == 0) 39 | { 40 | machine.InstructionPointer = Bracket[machine.InstructionPointer]; 41 | } 42 | }); 43 | vm.RegisterCommand(']', machine => 44 | { 45 | if (machine.Memory[machine.MemoryPointer] != 0) 46 | { 47 | machine.InstructionPointer = ClosingBracket[machine.InstructionPointer]; 48 | } 49 | }); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /4.Делегаты/VirtualMachine.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла VirtualMachine.cs 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace func.brainfuck 6 | { 7 | public class VirtualMachine : IVirtualMachine 8 | { 9 | public string Instructions { get; } 10 | public int InstructionPointer { get; set; } 11 | public byte[] Memory { get; } 12 | public int MemoryPointer { get; set; } 13 | int Size; 14 | Dictionary> registerCommand = new Dictionary>(); 15 | 16 | public VirtualMachine(string program, int memorySize) 17 | { 18 | Instructions = program; 19 | Size = memorySize; 20 | Memory = new byte[Size]; 21 | } 22 | 23 | public void RegisterCommand(char symbol, Action execute) 24 | { 25 | registerCommand.Add(symbol, execute); 26 | } 27 | 28 | public void Run() 29 | { 30 | for (; InstructionPointer < Instructions.Length; InstructionPointer++) 31 | { 32 | var command = Instructions[InstructionPointer]; 33 | if (registerCommand.ContainsKey(command)) 34 | { 35 | registerCommand[command](this); 36 | } 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /5.Функциональное программирование/ControlTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace func_rocket 4 | { 5 | public class ControlTask 6 | { 7 | public static double TotalAngle; 8 | 9 | public static Turn ControlRocket(Rocket rocket, Vector target) 10 | { 11 | var distanceVector = new Vector(target.X - rocket.Location.X, target.Y - rocket.Location.Y); 12 | 13 | if (Math.Abs(distanceVector.Angle - rocket.Direction) < 0.5 14 | || Math.Abs(distanceVector.Angle - rocket.Velocity.Angle) < 0.5) 15 | { 16 | TotalAngle = (distanceVector.Angle - rocket.Direction + distanceVector.Angle - rocket.Velocity.Angle) /2; 17 | } 18 | else 19 | { 20 | TotalAngle = distanceVector.Angle - rocket.Direction; 21 | } 22 | 23 | if (TotalAngle < 0) 24 | return Turn.Left; 25 | return TotalAngle > 0 ? Turn.Right : Turn.None; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /5.Функциональное программирование/ForcesTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла ForcesTask.cs 2 | using System; 3 | using System.Drawing; 4 | using System.Linq; 5 | 6 | namespace func_rocket 7 | { 8 | public class ForcesTask 9 | { 10 | /// 11 | /// Создает делегат, возвращающий по ракете вектор силы тяги двигателей этой ракеты. 12 | /// Сила тяги направлена вдоль ракеты и равна по модулю forceValue. 13 | /// 14 | public static RocketForce GetThrustForce(double forceValue) 15 | { 16 | return r => new Vector(Math.Cos(r.Direction) * forceValue, Math.Sin(r.Direction) * forceValue); 17 | } 18 | 19 | /// 20 | /// Преобразует делегат силы гравитации, в делегат силы, действующей на ракету 21 | /// 22 | public static RocketForce ConvertGravityToForce(Gravity gravity, Size spaceSize) 23 | { 24 | return r => gravity(spaceSize, r.Location); 25 | } 26 | 27 | /// 28 | /// Суммирует все переданные силы, действующие на ракету, и возвращает суммарную силу. 29 | /// 30 | public static RocketForce Sum(params RocketForce[] forces) 31 | { 32 | return r => 33 | { 34 | var result = Vector.Zero; 35 | foreach (var force in forces) 36 | result += force(r); 37 | return result; 38 | }; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /5.Функциональное программирование/LevelsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла LevelsTask.cs 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace func_rocket 6 | { 7 | public class LevelsTask 8 | { 9 | static readonly Physics standardPhysics = new Physics(); 10 | 11 | public static IEnumerable CreateLevels() 12 | { 13 | yield return new Level("Zero", 14 | new Rocket(new Vector(200, 500), Vector.Zero, -0.5 * Math.PI), 15 | new Vector(600, 200), 16 | (size, v) => Vector.Zero, standardPhysics); 17 | yield return new Level("Heavy", 18 | new Rocket(new Vector(200, 500), Vector.Zero, -0.5 * Math.PI), 19 | new Vector(600, 200), 20 | (size, v) => new Vector(0, 0.9), standardPhysics); 21 | yield return new Level("Up", 22 | new Rocket(new Vector(200, 500), Vector.Zero, -0.5 * Math.PI), 23 | new Vector(700, 500), 24 | (size, v) => new Vector(0, -300 / (size.Height - v.Y +300)), 25 | standardPhysics); 26 | yield return new Level("WhiteHole", 27 | new Rocket(new Vector(200, 500), Vector.Zero, -0.5 * Math.PI), 28 | new Vector(600, 200), 29 | (size, v) => 30 | { 31 | var toWhiteHole = new Vector(v.X - 600, v.Y - 200); 32 | return toWhiteHole.Normalize() * 140 * toWhiteHole.Length 33 | / (toWhiteHole.Length * toWhiteHole.Length + 1); 34 | }, 35 | standardPhysics); 36 | yield return new Level("BlackHole", 37 | new Rocket(new Vector(200, 500), Vector.Zero, -0.5 * Math.PI), 38 | new Vector(600, 200), 39 | (size, v) => 40 | { 41 | var blackHolePosition = new Vector((600 + 200) / 2 , (500 + 200) / 2); 42 | var toBlackHole = blackHolePosition - v; 43 | return new Vector(blackHolePosition.X - v.X, blackHolePosition.Y - v.Y).Normalize() * 44 | 300 * toBlackHole.Length / (toBlackHole.Length * toBlackHole.Length + 1); 45 | } 46 | , standardPhysics); 47 | yield return new Level("BlackAndWhite", 48 | new Rocket(new Vector(200, 500), Vector.Zero, -0.5 * Math.PI), 49 | new Vector(600, 200), 50 | (size, v) => 51 | { 52 | var toWhiteHole = new Vector(v.X - 600, v.Y - 200); 53 | var blackHolePosition = new Vector((600 + 200) / 2, (500 + 200) / 2); 54 | var toBlackHole = blackHolePosition - v; 55 | return (toWhiteHole.Normalize() * 140 * toWhiteHole.Length 56 | / (toWhiteHole.Length * toWhiteHole.Length + 1) + 57 | new Vector(blackHolePosition.X - v.X, blackHolePosition.Y - v.Y).Normalize() * 58 | 300 * toBlackHole.Length / (toBlackHole.Length * toBlackHole.Length + 1)) / 2; 59 | } 60 | , standardPhysics); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /6.LINQ/ExtensionsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла ExtensionsTask.cs 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace linq_slideviews 7 | { 8 | public static class ExtensionsTask 9 | { 10 | /// 11 | /// Медиана списка из нечетного количества элементов — это серединный элемент списка после сортировки. 12 | /// Медиана списка из четного количества элементов — среднее арифметическое двух серединных элементов списка после сортировки. 13 | /// 14 | /// Если последовательность не содержит элементов 15 | public static double Median(this IEnumerable items) 16 | { 17 | int count = 0; 18 | 19 | List sortedList = new List(); 20 | 21 | foreach (var item in items) 22 | { 23 | sortedList.Add(item); 24 | count++; 25 | } 26 | if (count > 0) 27 | { 28 | bool even = count % 2 == 0; 29 | 30 | sortedList.Sort(); 31 | 32 | return !even ? 33 | sortedList.ElementAt(count / 2) : 34 | (sortedList.ElementAt(count / 2) + sortedList.ElementAt((count / 2) - 1)) / 2.0; 35 | } 36 | else throw new InvalidOperationException(); 37 | } 38 | 39 | /// 40 | /// Возвращает последовательность, состоящую из пар соседних элементов. 41 | /// Например, по последовательности {1,2,3} метод должен вернуть две пары: (1,2) и (2,3). 42 | /// 43 | public static IEnumerable> Bigrams(this IEnumerable items) 44 | { 45 | var iterator = items.GetEnumerator(); 46 | iterator.MoveNext(); 47 | var past = iterator.Current; 48 | 49 | while(iterator.MoveNext()) 50 | { 51 | yield return Tuple.Create(past, iterator.Current); 52 | past = iterator.Current; 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /6.LINQ/ParsingTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | 6 | namespace linq_slideviews 7 | { 8 | public class ParsingTask 9 | { 10 | public static IDictionary ParseSlideRecords(IEnumerable lines) 11 | { 12 | return 13 | lines.Skip(1) 14 | .Select(line => line.Split(';')) 15 | .Select(ParseSlideRecord) 16 | .Where(slideRecord => slideRecord != null) 17 | .ToDictionary(slideRecord => slideRecord.SlideId); 18 | } 19 | 20 | public static IEnumerable ParseVisitRecords( 21 | IEnumerable lines, IDictionary slides) 22 | { 23 | return lines.Skip(1).Select(line => ParseVisitRecord(slides, line)); 24 | } 25 | 26 | private static VisitRecord ParseVisitRecord(IDictionary slides, string line) 27 | { 28 | try 29 | { 30 | var data = line.Split(';'); 31 | var slideId = int.Parse(data[1]); 32 | return new VisitRecord( 33 | int.Parse(data[0]), 34 | slideId, 35 | DateTime.ParseExact( 36 | data[2] + ' ' + data[3], 37 | "yyyy-MM-dd HH:mm:ss", 38 | CultureInfo.InvariantCulture, 39 | DateTimeStyles.None), slides[slideId].SlideType); 40 | } 41 | catch (Exception e) 42 | { 43 | throw new FormatException($"Wrong line [{line}]", e); 44 | } 45 | } 46 | 47 | private static SlideRecord ParseSlideRecord(string[] data) 48 | { 49 | if (data.Length != 3) 50 | return null; 51 | 52 | int id; 53 | if (!int.TryParse(data[0], out id)) 54 | return null; 55 | 56 | SlideType type; 57 | if (!Enum.TryParse(data[1], true, out type)) 58 | return null; 59 | 60 | return new SlideRecord(id, type, data[2]); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /6.LINQ/StatisticsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла StatisticsTask.cs 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace linq_slideviews 7 | { 8 | public class StatisticsTask 9 | { 10 | private static double savedValue = 0; 11 | private static bool sameSlide = false; 12 | 13 | public static double GetMedianTimePerSlide(List visits, SlideType slideType) 14 | { 15 | return visits 16 | .GroupBy(visit => visit.UserId) 17 | .Select(group => group.OrderBy(x => x.DateTime) 18 | .Bigrams()) 19 | .Select(bigram => GetAllTimes(bigram, slideType)) 20 | .SelectMany(x => x) 21 | .Where(time=> time >= 1 && time <= 120) 22 | .ToList() 23 | .DefaultIfEmpty(0) 24 | .Median(); 25 | } 26 | 27 | private static IEnumerable GetAllTimes(IEnumerable> visits, SlideType slideType) 28 | { 29 | return visits 30 | .Where(visit => visit.Item1.UserId.Equals(visit.Item2.UserId)) 31 | .Where(x => CheckForSlideId(x) && x.Item1.SlideType == slideType) 32 | .Select(visit => visit.Item2.DateTime.Subtract(visit.Item1.DateTime).TotalMinutes + savedValue); 33 | } 34 | 35 | private static double GetTime(Tuple visits) 36 | { 37 | if (!visits.Item1.UserId.Equals(visits.Item2.UserId)) return 0; 38 | return visits.Item2.DateTime.Subtract(visits.Item1.DateTime).TotalMinutes; 39 | } 40 | 41 | private static bool CheckForSlideId(Tuple visit) 42 | { 43 | if (visit.Item1.SlideId.Equals(visit.Item2.SlideId)) 44 | { 45 | sameSlide = true; 46 | savedValue += visit.Item2.DateTime.Subtract(visit.Item1.DateTime).TotalMinutes; 47 | return false; 48 | } 49 | else if (sameSlide) 50 | { 51 | sameSlide = false; 52 | return true; 53 | } 54 | savedValue = 0; 55 | return true; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /7.Графы и обходы/BfsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла BfsTask.cs 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Dungeon 11 | { 12 | public class BfsTask 13 | { 14 | public static IEnumerable> FindPaths(Map map, Point start, Point[] chests) 15 | { 16 | var queue = new Queue(); 17 | var visited = new HashSet(); 18 | var ways = new Dictionary>(); 19 | 20 | visited.Add(start); 21 | queue.Enqueue(start); 22 | ways.Add(start, new SinglyLinkedList(start)); 23 | 24 | while (queue.Count != 0) 25 | { 26 | var point = queue.Dequeue(); 27 | if (point.X < 0 || point.X >= map.Dungeon.GetLength(0) || point.Y < 0 || point.Y >= map.Dungeon.GetLength(1)) continue; 28 | if (map.Dungeon[point.X, point.Y] != MapCell.Empty) continue; 29 | 30 | for (var dy = -1; dy <= 1; dy++) 31 | for (var dx = -1; dx <= 1; dx++) 32 | { 33 | if (dx != 0 && dy != 0) continue; 34 | var nextPoint = new Point {X = point.X + dx, Y = point.Y + dy}; 35 | 36 | if (visited.Contains(nextPoint)) continue; 37 | 38 | queue.Enqueue(nextPoint); 39 | visited.Add(nextPoint); 40 | ways.Add(nextPoint, new SinglyLinkedList(nextPoint, ways[point])); 41 | } 42 | } 43 | 44 | foreach (var chest in chests) 45 | { 46 | if (ways.ContainsKey(chest)) yield return ways[chest]; 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /7.Графы и обходы/DungeonTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Dungeon 10 | { 11 | public class DungeonTask 12 | { 13 | public static MoveDirection[] FindShortestPath(Map map) 14 | { 15 | //Путь до выхода 16 | var pathToExit = BfsTask.FindPaths(map, map.InitialPosition, new[] { map.Exit }).FirstOrDefault(); 17 | //Если нет пути до выхода 18 | if (pathToExit == null) 19 | return new MoveDirection[0]; 20 | 21 | //Если найденый путь до выхода содержит хоть один сундук 22 | if (map.Chests.Any(chest => pathToExit.ToList().Contains(chest))) 23 | return pathToExit.ToList().ParseToDirections(); 24 | 25 | //Находим кратчайший путь 26 | var chests = BfsTask.FindPaths(map, map.InitialPosition, map.Chests); 27 | var result = chests.Select(chest => Tuple.Create( 28 | chest, BfsTask.FindPaths(map, chest.Value, new[] { map.Exit }).FirstOrDefault())) 29 | .MinElement(); 30 | //Если кратчайший путь не проходит ни через один сундук 31 | if (result == null) return pathToExit.ToList().ParseToDirections(); 32 | 33 | //Парсим каждую часть пути (до сундука и от него) в путь MoveDirection и соединяем 34 | return result.Item1.ToList().ParseToDirections().Concat( 35 | result.Item2.ToList().ParseToDirections()) 36 | .ToArray(); 37 | } 38 | } 39 | 40 | public static class ExtentionMetods 41 | { 42 | //Поиск минимального пути, к котором путь до сундука и от него до выхода 43 | //Суммарно будут кратчайшими 44 | public static Tuple, SinglyLinkedList> 45 | MinElement(this IEnumerable, SinglyLinkedList>> items) 46 | { 47 | if (items.Count() == 0 || items.First().Item2 == null) 48 | return null; 49 | 50 | var min = int.MaxValue; 51 | var minElement = items.First(); 52 | foreach (var element in items) 53 | if (element.Item1.Length + element.Item2.Length < min) 54 | { 55 | min = element.Item1.Length + element.Item2.Length; 56 | minElement = element; 57 | } 58 | return minElement; 59 | } 60 | 61 | //Перевод из последовательности точек к последовательность направлений 62 | public static MoveDirection[] ParseToDirections(this List items) 63 | { 64 | var resultList = new List(); 65 | if (items == null) 66 | return new MoveDirection[0]; 67 | var itemsLength = items.Count; 68 | 69 | for (var i = itemsLength - 1; i > 0; i--) 70 | { 71 | resultList.Add(GetDirection(items[i], items[i - 1])); 72 | } 73 | return resultList.ToArray(); 74 | } 75 | 76 | //Направление между двумя точками 77 | static MoveDirection GetDirection(Point firstPoint, Point secondPoint) 78 | { 79 | var newPoint = new Point(firstPoint.X - secondPoint.X, firstPoint.Y - secondPoint.Y); 80 | if (newPoint.X == 1) return MoveDirection.Left; 81 | if (newPoint.X == -1) return MoveDirection.Right; 82 | if (newPoint.Y == 1) return MoveDirection.Up; 83 | if (newPoint.Y == -1) return MoveDirection.Down; 84 | throw new ArgumentException(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /7.Графы и обходы/RivalsTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Rivals 10 | { 11 | public class RivalsTask 12 | { 13 | public static IEnumerable AssignOwners(Map map) 14 | { 15 | var queue = new Queue>(); 16 | var visited = new HashSet(); 17 | for (int i = 0; i < map.Players.Length; i++) 18 | { 19 | queue.Enqueue(Tuple.Create(new Point(map.Players[i].X, 20 | map.Players[i].Y), i, 0)); 21 | } 22 | 23 | while (queue.Count != 0) 24 | { 25 | var dequeued = queue.Dequeue(); 26 | var point = dequeued.Item1; 27 | if (point.X < 0 || point.X >= map.Maze.GetLength(0) 28 | || point.Y < 0 || point.Y >= map.Maze.GetLength(1)) continue; 29 | if (map.Maze[point.X, point.Y] == MapCell.Wall) continue; 30 | if (visited.Contains(point)) continue; 31 | visited.Add(point); 32 | yield return new OwnedLocation(dequeued.Item2, 33 | new Point(point.X, point.Y), dequeued.Item3); 34 | for (var dy = -1; dy <= 1; dy++) 35 | for (var dx = -1; dx <= 1; dx++) 36 | if (dx != 0 && dy != 0) continue; 37 | else queue.Enqueue(Tuple.Create(new Point { 38 | X = point.X + dx, 39 | Y = point.Y + dy }, 40 | dequeued.Item2, dequeued.Item3 + 1)); 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /8.Жадные алгоритмы/GreedyPathFinder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using Greedy.Architecture; 4 | using Greedy.Architecture.Drawing; 5 | 6 | namespace Greedy 7 | { 8 | public class GreedyPathFinder : IPathFinder 9 | { 10 | public List FindPathToCompleteGoal(State state) 11 | { 12 | if (state.Chests.Count < state.Goal) 13 | { 14 | return new List(); 15 | } 16 | 17 | var unpickedChests = new HashSet(state.Chests); 18 | var pickedChestsNumber = 0; 19 | 20 | var path = new List(); 21 | var currentEnergy = state.InitialEnergy; 22 | var currentPosition = state.Position; 23 | 24 | while (pickedChestsNumber < state.Goal) 25 | { 26 | int wastedEnergy; 27 | 28 | var pathToNextChest = GetPathToNextChest(unpickedChests, currentPosition, state, out wastedEnergy); 29 | 30 | currentEnergy -= wastedEnergy; 31 | if (currentEnergy < 0 || pathToNextChest == null) 32 | { 33 | return new List(); 34 | } 35 | 36 | path.AddRange(pathToNextChest); 37 | 38 | if (pathToNextChest.Count > 0) 39 | { 40 | currentPosition = pathToNextChest[pathToNextChest.Count - 1]; 41 | } 42 | 43 | unpickedChests.Remove(currentPosition); 44 | pickedChestsNumber++; 45 | } 46 | 47 | 48 | return path; 49 | } 50 | 51 | private List GetPathToNextChest(HashSet chests, 52 | Point startPoint, State state, out int wastedEnergy) 53 | { 54 | var passedPoints = new Dictionary(); 55 | var markedPoints = new Dictionary(); 56 | 57 | markedPoints.Add(startPoint, new MovingData(startPoint, 0)); 58 | 59 | Point lastPoint; 60 | while (true) 61 | { 62 | if (markedPoints.Count == 0) 63 | { 64 | wastedEnergy = 0; 65 | return null; 66 | } 67 | 68 | var openingPoint = GetOpeningPoint(markedPoints); 69 | 70 | passedPoints.Add(openingPoint, markedPoints[openingPoint]); 71 | markedPoints.Remove(openingPoint); 72 | 73 | if (chests.Contains(openingPoint)) 74 | { 75 | lastPoint = openingPoint; 76 | break; 77 | } 78 | 79 | foreach (var nextPoint in Environs(openingPoint)) 80 | { 81 | if (passedPoints.ContainsKey(nextPoint) || !state.InsideMap(nextPoint) || state.IsWallAt(nextPoint)) 82 | { 83 | continue; 84 | } 85 | 86 | var energyForNextPoint = state.CellCost[nextPoint.X, nextPoint.Y] 87 | + passedPoints[openingPoint].WastedEnergy; 88 | 89 | UpdateMarkedPoints(markedPoints, nextPoint, energyForNextPoint, openingPoint); 90 | } 91 | } 92 | 93 | wastedEnergy = passedPoints[lastPoint].WastedEnergy; 94 | 95 | return GetResult(passedPoints, startPoint, lastPoint); 96 | } 97 | 98 | private Point GetOpeningPoint(Dictionary markedPoints) 99 | { 100 | var openingPoint = default(Point); 101 | var energyToPoint = int.MaxValue; 102 | 103 | foreach (var point in markedPoints.Keys) 104 | { 105 | if (markedPoints[point].WastedEnergy < energyToPoint) 106 | { 107 | openingPoint = point; 108 | energyToPoint = markedPoints[point].WastedEnergy; 109 | } 110 | } 111 | 112 | return openingPoint; 113 | } 114 | 115 | private IEnumerable Environs(Point current) 116 | { 117 | for (int x = current.X - 1; x < current.X + 2; x++) 118 | { 119 | for (int y = current.Y - 1; y < current.Y + 2; y++) 120 | { 121 | if (x == current.X || y == current.Y) 122 | { 123 | yield return new Point(x, y); 124 | } 125 | } 126 | } 127 | } 128 | 129 | private void UpdateMarkedPoints(Dictionary markedPoints, 130 | Point nextPoint, int energyForNextPoint, Point previousPoint) 131 | { 132 | if (markedPoints.TryGetValue(nextPoint, out var alreadyMarkedInfo)) 133 | { 134 | if (alreadyMarkedInfo.WastedEnergy <= energyForNextPoint) 135 | { 136 | return; 137 | } 138 | } 139 | 140 | markedPoints[nextPoint] = new MovingData(previousPoint, energyForNextPoint); 141 | } 142 | 143 | private List GetResult(Dictionary passedPoints, Point startPoint, Point lastPoint) 144 | { 145 | var result = new List(); 146 | 147 | while (lastPoint != startPoint) 148 | { 149 | result.Add(lastPoint); 150 | lastPoint = passedPoints[lastPoint].Previous; 151 | } 152 | 153 | result.Reverse(); 154 | 155 | return result; 156 | } 157 | 158 | class MovingData 159 | { 160 | public Point Previous { get; set; } 161 | public int WastedEnergy { get; set; } 162 | 163 | public MovingData(Point previous, int wastedEnergy) 164 | { 165 | Previous = previous; 166 | WastedEnergy = wastedEnergy; 167 | } 168 | } 169 | } 170 | } -------------------------------------------------------------------------------- /8.Жадные алгоритмы/NotGreedyPathFinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using Greedy.Architecture; 6 | using Greedy.Architecture.Drawing; 7 | 8 | namespace Greedy 9 | { 10 | public class NotGreedyPathFinder : IPathFinder 11 | { 12 | public const int Limiter = 8; 13 | 14 | public List FindPathToCompleteGoal(State state) 15 | { 16 | var graph = new Graph(state.MapHeight * state.MapWidth); 17 | var weights = new Dictionary(); 18 | var chests = state.Chests.Take(Limiter); 19 | 20 | var pathsBetweenChests = new Dictionary>>(); 21 | 22 | InitializeGraphOnCells(state, weights, graph); 23 | 24 | pathsBetweenChests[state.Position] = GetPathToAllChests(graph, weights, state.Position, state); 25 | 26 | foreach (var chest in chests) 27 | pathsBetweenChests[chest] = GetPathToAllChests(graph, weights, chest, state); 28 | 29 | var bestPath = new List(); 30 | 31 | for (var i = 1; i <= Limiter; i++) 32 | { 33 | var reachableChestPermutations = GetPermutations(chests, i) 34 | .Where(perm => PathsPermutationStaminaCost(state, perm, pathsBetweenChests) <= state.Energy); 35 | 36 | if (!reachableChestPermutations.Any()) 37 | break; 38 | 39 | bestPath = reachableChestPermutations 40 | .First() 41 | .ToList(); 42 | } 43 | 44 | 45 | return GetTotalPathByPermutation(state, bestPath, pathsBetweenChests); 46 | } 47 | 48 | private static Dictionary> GetPathToAllChests(Graph graph, Dictionary weights, 49 | Point start, State state) 50 | { 51 | var result = new Dictionary>(); 52 | var chests = state.Chests.Where(chest => chest != start); 53 | 54 | foreach (var chest in chests) 55 | result[chest] = GetPathToChest(graph, weights, state, start, chest); 56 | 57 | return result; 58 | } 59 | 60 | private static List GetPathToChest(Graph graph, Dictionary weights, 61 | State state, Point start, Point chest) 62 | { 63 | var initialPositionNumber = GetPointNumber(start, state.MapWidth); 64 | var chestPositionNumber = GetPointNumber(chest, state.MapWidth); 65 | 66 | var path = Dijkstra(graph, weights, graph[initialPositionNumber], graph[chestPositionNumber]); 67 | 68 | return path?.Select(n => CreatePointByNumber(n.NodeNumber, state.MapWidth)).Skip(1).ToList() ?? 69 | new List(); 70 | } 71 | 72 | private static int PathStaminaCost(State state, IEnumerable path) 73 | { 74 | return path.Sum(point => state.CellCost[point.X, point.Y]); 75 | } 76 | 77 | private static int PathsPermutationStaminaCost(State state, IEnumerable chests, 78 | Dictionary>> pathsBetweenChests) 79 | { 80 | var current = state.Position; 81 | var total = 0; 82 | 83 | foreach (var chest in chests) 84 | { 85 | total += PathStaminaCost(state, pathsBetweenChests[current][chest]); 86 | current = chest; 87 | } 88 | 89 | return total; 90 | } 91 | 92 | private static List GetTotalPathByPermutation(State state, ICollection pointsPermutation, 93 | Dictionary>> pathsBetweenChests) 94 | { 95 | var current = state.Position; 96 | var result = new List(); 97 | 98 | foreach (var point in pointsPermutation) 99 | { 100 | result.AddRange(pathsBetweenChests[current][point]); 101 | current = point; 102 | } 103 | 104 | return result; 105 | } 106 | 107 | private static IEnumerable> GetPermutations(IEnumerable list, int length) 108 | { 109 | if (length == 1) return list.Select(t => new[] { t }); 110 | return GetPermutations(list, length - 1) 111 | .SelectMany(t => list.Where(o => !t.Contains(o)), 112 | (t1, t2) => t1.Concat(new[] { t2 })); 113 | } 114 | 115 | private static void InitializeGraphOnCells(State state, IDictionary weights, Graph graph) 116 | { 117 | for (var y = 0; y < state.MapHeight; y++) 118 | for (var x = 0; x < state.MapWidth; x++) 119 | { 120 | var point = new Point(x, y); 121 | 122 | for (var dy = -1; dy <= 1; dy++) 123 | for (var dx = -1; dx <= 1; dx++) 124 | { 125 | if (dx != 0 && dy != 0) continue; 126 | var neighbour = new Point(x + dx, y + dy); 127 | if (!state.InsideMap(neighbour)) continue; 128 | if (state.IsWallAt(neighbour)) continue; 129 | 130 | var pointNumber = GetPointNumber(point, state.MapWidth); 131 | var neighbourNumber = GetPointNumber(neighbour, state.MapWidth); 132 | weights[graph.Connect(pointNumber, neighbourNumber)] = state.CellCost[neighbour.X, neighbour.Y]; 133 | } 134 | } 135 | } 136 | 137 | private static int GetPointNumber(Point point, int mapWidth) 138 | { 139 | return point.Y * mapWidth + point.X; 140 | } 141 | 142 | private static Point CreatePointByNumber(int pointNumber, int mapWidth) 143 | { 144 | return new Point(pointNumber % mapWidth, pointNumber / mapWidth); 145 | } 146 | 147 | private static List Dijkstra(Graph graph, Dictionary weights, Node start, Node end) 148 | { 149 | var notVisited = graph.Nodes.ToList(); 150 | var track = new Dictionary(); 151 | track[start] = new DijkstraData { Price = 0, Previous = null }; 152 | 153 | while (true) 154 | { 155 | Node toOpen = null; 156 | var bestPrice = double.PositiveInfinity; 157 | foreach (var e in notVisited) 158 | if (track.ContainsKey(e) && track[e].Price < bestPrice) 159 | { 160 | bestPrice = track[e].Price; 161 | toOpen = e; 162 | } 163 | 164 | if (toOpen == null) return null; 165 | if (toOpen == end) break; 166 | 167 | foreach (var e in toOpen.IncidentEdges.Where(z => z.From == toOpen)) 168 | { 169 | var currentPrice = track[toOpen].Price + weights[e]; 170 | var nextNode = e.OtherNode(toOpen); 171 | if (!track.ContainsKey(nextNode) || track[nextNode].Price > currentPrice) 172 | track[nextNode] = new DijkstraData { Previous = toOpen, Price = currentPrice }; 173 | } 174 | 175 | notVisited.Remove(toOpen); 176 | } 177 | 178 | var result = new List(); 179 | while (end != null) 180 | { 181 | result.Add(end); 182 | end = track[end].Previous; 183 | } 184 | result.Reverse(); 185 | return result; 186 | } 187 | 188 | internal class DijkstraData 189 | { 190 | public Node Previous { get; set; } 191 | public double Price { get; set; } 192 | } 193 | 194 | internal class Edge 195 | { 196 | public readonly Node From; 197 | public readonly Node To; 198 | 199 | public Edge(Node first, Node second) 200 | { 201 | From = first; 202 | To = second; 203 | } 204 | 205 | public bool IsIncident(Node node) 206 | { 207 | return From == node || To == node; 208 | } 209 | 210 | public Node OtherNode(Node node) 211 | { 212 | if (!IsIncident(node)) throw new ArgumentException(); 213 | if (From == node) return To; 214 | return From; 215 | } 216 | } 217 | 218 | internal class Node 219 | { 220 | private readonly List edges = new List(); 221 | public readonly int NodeNumber; 222 | 223 | public Node(int number) 224 | { 225 | NodeNumber = number; 226 | } 227 | 228 | public IEnumerable IncidentNodes 229 | { 230 | get { return edges.Select(z => z.OtherNode(this)); } 231 | } 232 | 233 | public IEnumerable IncidentEdges 234 | { 235 | get 236 | { 237 | foreach (var e in edges) yield return e; 238 | } 239 | } 240 | 241 | public static Edge Connect(Node node1, Node node2, Graph graph) 242 | { 243 | if (!graph.Nodes.Contains(node1) || !graph.Nodes.Contains(node2)) throw new ArgumentException(); 244 | var edge = new Edge(node1, node2); 245 | node1.edges.Add(edge); 246 | return edge; 247 | } 248 | } 249 | 250 | internal class Graph 251 | { 252 | private readonly Node[] nodes; 253 | 254 | public Graph(int nodesCount) 255 | { 256 | nodes = Enumerable.Range(0, nodesCount).Select(z => new Node(z)).ToArray(); 257 | } 258 | 259 | public int Length => nodes.Length; 260 | 261 | public Node this[int index] => nodes[index]; 262 | 263 | public IEnumerable Nodes 264 | { 265 | get 266 | { 267 | foreach (var node in nodes) yield return node; 268 | } 269 | } 270 | 271 | public IEnumerable Edges 272 | { 273 | get { return nodes.SelectMany(z => z.IncidentEdges).Distinct(); } 274 | } 275 | 276 | public Edge Connect(int index1, int index2) 277 | { 278 | return Node.Connect(nodes[index1], nodes[index2], this); 279 | } 280 | 281 | public static Graph MakeGraph(params int[] incidentNodes) 282 | { 283 | var graph = new Graph(incidentNodes.Max() + 1); 284 | for (var i = 0; i < incidentNodes.Length - 1; i += 2) 285 | graph.Connect(incidentNodes[i], incidentNodes[i + 1]); 286 | return graph; 287 | } 288 | } 289 | } 290 | } -------------------------------------------------------------------------------- /9.Динамическое программирование/FlagsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла FlagsTask.cs 2 | namespace Flags 3 | { 4 | public static class FlagsTask 5 | { 6 | public static long Solve(int a) 7 | { 8 | long prev = 1, current = 1, result = 1; 9 | for (long i = 2; i < a; i++) 10 | { 11 | result = prev + current; 12 | prev = current; 13 | current = result; 14 | } 15 | return result * 2; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /9.Динамическое программирование/TicketsTask.cs: -------------------------------------------------------------------------------- 1 | // Вставьте сюда финальное содержимое файла TicketsTask.cs 2 | using System.Numerics; 3 | 4 | namespace Tickets 5 | { 6 | internal class TicketsTask 7 | { 8 | private const int MaxLen = 100; 9 | private const int MaxSum = 2000; 10 | 11 | public static BigInteger Solve(int halfLen, int totalSum) 12 | { 13 | if (totalSum % 2 != 0) 14 | return 0; 15 | 16 | var happyTickets = InitializeHappyTicketsContainer(); 17 | 18 | var halfResult = CountHappyTickets(happyTickets, halfLen, totalSum / 2); 19 | return halfResult * halfResult; 20 | } 21 | 22 | private static BigInteger[,] InitializeHappyTicketsContainer() 23 | { 24 | var happyTickets = new BigInteger[MaxLen + 1, MaxSum + 1]; 25 | 26 | for (var i = 0; i < MaxLen; i++) 27 | for (var j = 0; j < MaxSum; j++) 28 | { 29 | happyTickets[i, j] = -1; 30 | } 31 | 32 | return happyTickets; 33 | } 34 | 35 | private static BigInteger CountHappyTickets(BigInteger[,] happyTickets, int len, int sum) 36 | { 37 | if (happyTickets[len, sum] >= 0) return happyTickets[len, sum]; 38 | if (sum == 0) return 1; 39 | if (len == 0) return 0; 40 | 41 | happyTickets[len, sum] = 0; 42 | for (var i = 0; i < 10; i++) 43 | { 44 | if (sum - i >= 0) 45 | { 46 | happyTickets[len, sum] += CountHappyTickets(happyTickets, len - 1, sum - i); 47 | } 48 | } 49 | 50 | return happyTickets[len, sum]; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ulearn-sharp2- 2 | 3 | Прохождение курса "Основы программирования на примере C#"-Часть2 4 | 5 | Курс на сайте https://ulearn.me/ 6 | 7 | Весь проект задания скачивается со страницы задания. 8 | --------------------------------------------------------------------------------