using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using YukicoderContest273.Extensions; using YukicoderContest273.Questions; using YukicoderContest273.Graphs; using YukicoderContest273.Graphs.Algorithms; namespace YukicoderContest273.Questions { public class QuestionE : AtCoderQuestionBase { public override IEnumerable Solve(TextReader inputStream) { var (n, feeCount) = inputStream.ReadValue(); var nodeCount = n * n; var feeMap = new int[n, n]; for (int i = 0; i < feeCount; i++) { var (r, c, cost) = inputStream.ReadValue(); r--; c--; feeMap[r, c] = cost; } var graph = new WeightedGraph(nodeCount * 2); var diffs = new (int dr, int dc)[] { (-1, 0), (1, 0), (0, -1), (0, 1) }; for (int row = 0; row < n; row++) { for (int column = 0; column < n; column++) { foreach (var diff in diffs) { var (dr, dc) = diff; var nextRow = row + dr; var nextColumn = column + dc; if (unchecked((uint)nextRow < (uint)n && (uint)nextColumn < (uint)n)) { graph[GetIndex(row, column, n)].Add(new WeightedEdge(GetIndex(nextRow, nextColumn, n), 1 + feeMap[nextRow, nextColumn])); graph[GetIndex(row, column, n)].Add(new WeightedEdge(GetIndex(nextRow, nextColumn, n) + nodeCount, 1)); graph[GetIndex(row, column, n) + nodeCount].Add(new WeightedEdge(GetIndex(nextRow, nextColumn, n) + nodeCount, 1 + feeMap[nextRow, nextColumn])); } } } } var dijkstra = new Dijkstra(graph); var costs = dijkstra.GetDistancesFrom(0); yield return costs[costs.Length - 1]; } int GetIndex(int row, int column, int n) => row * n + column; } } namespace YukicoderContest273 { class Program { static void Main(string[] args) { IAtCoderQuestion question = new QuestionE(); var answers = question.Solve(Console.In); var writer = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }; Console.SetOut(writer); foreach (var answer in answers) { Console.WriteLine(answer); } Console.Out.Flush(); } } } #region Base Class namespace YukicoderContest273.Questions { public interface IAtCoderQuestion { IEnumerable Solve(string input); IEnumerable Solve(TextReader inputStream); } public abstract class AtCoderQuestionBase : IAtCoderQuestion { public IEnumerable Solve(string input) { var stream = new MemoryStream(Encoding.Unicode.GetBytes(input)); var reader = new StreamReader(stream, Encoding.Unicode); return Solve(reader); } public abstract IEnumerable Solve(TextReader inputStream); } } #endregion #region Extensions namespace YukicoderContest273.Extensions { public static class StringExtensions { public static string Join(this IEnumerable source) => string.Concat(source); public static string Join(this IEnumerable source, char separator) => string.Join(separator, source); public static string Join(this IEnumerable source, string separator) => string.Join(separator, source); } public static class TextReaderExtensions { public static int ReadInt(this TextReader reader) => int.Parse(ReadString(reader)); public static long ReadLong(this TextReader reader) => long.Parse(ReadString(reader)); public static double ReadDouble(this TextReader reader) => double.Parse(ReadString(reader)); public static string ReadString(this TextReader reader) => reader.ReadLine(); public static int[] ReadIntArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(int.Parse).ToArray(); public static long[] ReadLongArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(long.Parse).ToArray(); public static double[] ReadDoubleArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(double.Parse).ToArray(); public static string[] ReadStringArray(this TextReader reader, char separator = ' ') => reader.ReadLine().Split(separator); // Supports primitive type only. public static T1 ReadValue(this TextReader reader) => (T1)Convert.ChangeType(reader.ReadLine(), typeof(T1)); public static (T1, T2) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); return (v1, v2); } public static (T1, T2, T3) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3)); return (v1, v2, v3); } public static (T1, T2, T3, T4) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3)); var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4)); return (v1, v2, v3, v4); } public static (T1, T2, T3, T4, T5) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3)); var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4)); var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5)); return (v1, v2, v3, v4, v5); } public static (T1, T2, T3, T4, T5, T6) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3)); var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4)); var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5)); var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6)); return (v1, v2, v3, v4, v5, v6); } public static (T1, T2, T3, T4, T5, T6, T7) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3)); var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4)); var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5)); var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6)); var v7 = (T7)Convert.ChangeType(inputs[6], typeof(T7)); return (v1, v2, v3, v4, v5, v6, v7); } public static (T1, T2, T3, T4, T5, T6, T7, T8) ReadValue(this TextReader reader, char separator = ' ') { var inputs = ReadStringArray(reader, separator); var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1)); var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2)); var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3)); var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4)); var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5)); var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6)); var v7 = (T7)Convert.ChangeType(inputs[6], typeof(T7)); var v8 = (T8)Convert.ChangeType(inputs[7], typeof(T8)); return (v1, v2, v3, v4, v5, v6, v7, v8); } } } #endregion namespace YukicoderContest273.Graphs { public interface IEdge { int To { get; } } public interface IWeightedEdge : IEdge { long Weight { get; } } public interface IGraph where TEdge : IEdge { List this[int node] { get; } int NodeCount { get; } } public interface IWeightedGraph : IGraph where TEdge : IWeightedEdge { } public readonly struct BasicEdge : IEdge { public int To { get; } public BasicEdge(int to) { To = to; } public override string ToString() => To.ToString(); public static implicit operator BasicEdge(int edge) => new BasicEdge(edge); public static implicit operator int(BasicEdge edge) => edge.To; } [StructLayout(LayoutKind.Auto)] public readonly struct WeightedEdge : IWeightedEdge { public int To { get; } public long Weight { get; } public WeightedEdge(int to) : this(to, 1) { } public WeightedEdge(int to, long weight) { To = to; Weight = weight; } public override string ToString() => $"[{Weight}]-->{To}"; public void Deconstruct(out int to, out long weight) => (to, weight) = (To, Weight); } public class WeightedGraph : IGraph { private readonly List> _edges; public List this[int node] => _edges[node]; public int NodeCount => _edges.Count; public WeightedGraph(int nodeCount) { _edges = new List>(nodeCount); for (int i = 0; i < nodeCount; i++) { _edges.Add(new List()); } } public void AddEdge(int from, int to, long weight) => _edges[from].Add(new WeightedEdge(to, weight)); public void AddNode() => _edges.Add(new List()); } public class PriorityQueue : IEnumerable where T : IComparable { private List _heap = new List(); private readonly int _reverseFactor; public int Count => _heap.Count; public bool IsDescending => _reverseFactor == 1; public PriorityQueue(bool descending) : this(descending, null) { } public PriorityQueue(bool descending, IEnumerable collection) { _reverseFactor = descending ? 1 : -1; _heap = new List(); if (collection != null) { foreach (var item in collection) { Enqueue(item); } } } public void Enqueue(T item) { _heap.Add(item); UpHeap(); } public T Dequeue() { var item = _heap[0]; DownHeap(); return item; } public T Peek() => _heap[0]; private void UpHeap() { var child = Count - 1; while (child > 0) { int parent = (child - 1) / 2; if (Compare(_heap[child], _heap[parent]) > 0) { SwapAt(child, parent); child = parent; } else { break; } } } private void DownHeap() { _heap[0] = _heap[Count - 1]; _heap.RemoveAt(Count - 1); var parent = 0; while (true) { var leftChild = 2 * parent + 1; if (leftChild > Count - 1) { break; } var target = (leftChild < Count - 1) && (Compare(_heap[leftChild], _heap[leftChild + 1]) < 0) ? leftChild + 1 : leftChild; if (Compare(_heap[parent], _heap[target]) < 0) { SwapAt(parent, target); } else { break; } parent = target; } } private int Compare(T a, T b) => _reverseFactor * a.CompareTo(b); private void SwapAt(int n, int m) => (_heap[n], _heap[m]) = (_heap[m], _heap[n]); public IEnumerator GetEnumerator() { var copy = new List(_heap); try { while (Count > 0) { yield return Dequeue(); } } finally { _heap = copy; } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); } namespace Algorithms { public class Dijkstra { private readonly WeightedGraph _graph; public Dijkstra(WeightedGraph graph) { _graph = graph; } public long[] GetDistancesFrom(int startNode) { const long Inf = 1L << 60; var distances = Enumerable.Repeat(Inf, _graph.NodeCount).ToArray(); distances[startNode] = 0; var todo = new PriorityQueue(false); todo.Enqueue(new State(startNode, 0)); while (todo.Count > 0) { var current = todo.Dequeue(); if (current.Distance > distances[current.Node]) { continue; } for (int i = 0; i < _graph[current.Node].Count; i++) { var edge = _graph[current.Node][i]; var nextDistance = current.Distance + edge.Weight; if (distances[edge.To] > nextDistance) { distances[edge.To] = nextDistance; todo.Enqueue(new State(edge.To, nextDistance)); } } } return distances; } private readonly struct State : IComparable { public int Node { get; } public long Distance { get; } public State(int node, long distance) { Node = node; Distance = distance; } public int CompareTo(State other) => Distance.CompareTo(other.Distance); public void Deconstruct(out int node, out long distance) => (node, distance) = (Node, Distance); } } } }