using System; using System.Collections.Generic; using System.Linq; // ABC344-F Earn to Advance // https://atcoder.jp/contests/abc344/tasks/abc344_f class Program { static string InputPattern = "InputX"; static List<string> GetInputList() { var WillReturn = new List<string>(); if (InputPattern == "Input1") { WillReturn.Add("3"); WillReturn.Add("1 2 3"); WillReturn.Add("3 1 2"); WillReturn.Add("2 1 1"); WillReturn.Add("1 2"); WillReturn.Add("4 3"); WillReturn.Add("4 2"); WillReturn.Add("1 5 7"); WillReturn.Add("5 3 3"); //8 } else if (InputPattern == "Input2") { WillReturn.Add("3"); WillReturn.Add("1 1 1"); WillReturn.Add("1 1 1"); WillReturn.Add("1 1 1"); WillReturn.Add("1000000000 1000000000"); WillReturn.Add("1000000000 1000000000"); WillReturn.Add("1000000000 1000000000"); WillReturn.Add("1000000000 1000000000 1000000000"); WillReturn.Add("1000000000 1000000000 1000000000"); //4000000004 } else { string wkStr; while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr); } return WillReturn; } static int[,] mBanArr; static List<int[]> mYokoCostArrList = new List<int[]>(); static List<int[]> mTateCostArrList = new List<int[]>(); static int UB; static void Main() { List<string> InputList = GetInputList(); int N = int.Parse(InputList[0]); UB = N - 1; mBanArr = CreateBanArr(InputList.Skip(1).Take(N)); foreach (string EachStr in InputList.Skip(1 + N).Take(N)) { mYokoCostArrList.Add(EachStr.Split(' ').Select(pX => int.Parse(pX)).ToArray()); } foreach (string EachStr in InputList.Skip(1 + N + N)) { mTateCostArrList.Add(EachStr.Split(' ').Select(pX => int.Parse(pX)).ToArray()); } // 最小の行動回数[状態]なDP表 var PrevDP = new Dictionary<string, long>(); JyoutaiDef FirstJyoutai; FirstJyoutai.CurrX = 0; FirstJyoutai.CurrY = 0; FirstJyoutai.Money = 0; FirstJyoutai.MaxEran = mBanArr[0, 0]; PrevDP[GetHash(FirstJyoutai)] = 0; var AnswerList = new List<long>(); while (PrevDP.Count > 0) { var CurrDP = new Dictionary<string, long>(); foreach (var EachPair in PrevDP) { JyoutaiDef CurrJyoutai = GetJyoutai(EachPair.Key); long CurrX = CurrJyoutai.CurrX; long CurrY = CurrJyoutai.CurrY; Action<long, long> UpdateAct = (pNewX, pNewY) => { if (UB < pNewX || UB < pNewY) return; long PayMoney = DerivePayMoney(CurrX, CurrY, pNewX, pNewY); long NewMoney = CurrJyoutai.Money - PayMoney; long NewVal = EachPair.Value + 1; if (NewMoney < 0) { long Div = Math.Abs(NewMoney) / CurrJyoutai.MaxEran; if (Math.Abs(NewMoney) % CurrJyoutai.MaxEran > 0) { Div++; } NewVal += Div; NewMoney += CurrJyoutai.MaxEran * Div; } long NewMaxEran = Math.Max(CurrJyoutai.MaxEran, mBanArr[pNewX, pNewY]); // クリア判定 if (pNewX == UB && pNewY == UB) { AnswerList.Add(NewVal); return; } JyoutaiDef NewJyoutai; NewJyoutai.CurrX = pNewX; NewJyoutai.CurrY = pNewY; NewJyoutai.Money = NewMoney; NewJyoutai.MaxEran = NewMaxEran; string Hash = GetHash(NewJyoutai); if (CurrDP.ContainsKey(Hash)) { if (CurrDP[Hash] <= NewVal) { return; } } CurrDP[Hash] = NewVal; }; UpdateAct(CurrX, CurrY + 1); UpdateAct(CurrX + 1, CurrY); } PrevDP = CurrDP; } Console.WriteLine(AnswerList.Min()); } struct JyoutaiDef { internal long CurrX; internal long CurrY; internal long Money; // 残金 internal long MaxEran; // 最大日給 } static JyoutaiDef GetJyoutai(string pHash) { string[] SplitArr = pHash.Split(','); JyoutaiDef WillReturn; WillReturn.CurrX = long.Parse(SplitArr[0]); WillReturn.CurrY = long.Parse(SplitArr[1]); WillReturn.Money = long.Parse(SplitArr[2]); WillReturn.MaxEran = long.Parse(SplitArr[3]); return WillReturn; } static string GetHash(JyoutaiDef pJyoutai) { return string.Format("{0},{1},{2},{3}", pJyoutai.CurrX, pJyoutai.CurrY, pJyoutai.Money, pJyoutai.MaxEran); } // 移動元座標と、移動先座標を引数として支払う金額を返す static long DerivePayMoney(long pFromX, long pFromY, long pToX, long pToY) { if (pFromX != pToX) { return mYokoCostArrList[(int)pFromY][pFromX]; } else { return mTateCostArrList[(int)pFromY][pFromX]; } } //////////////////////////////////////////////////////////////// // IEnumerable<string>をintの2次元配列に設定する //////////////////////////////////////////////////////////////// static int[,] CreateBanArr(IEnumerable<string> pStrEnum) { var StrList = pStrEnum.ToList(); if (StrList.Count == 0) { return new int[0, 0]; } int[] IntArr = { }; Action<string> SplitAct = pStr => IntArr = pStr.Split(' ').Select(pX => int.Parse(pX)).ToArray(); SplitAct(StrList[0]); int UB_X = IntArr.GetUpperBound(0); int UB_Y = StrList.Count - 1; int[,] WillReturn = new int[UB_X + 1, UB_Y + 1]; for (int Y = 0; Y <= UB_Y; Y++) { SplitAct(StrList[Y]); for (int X = 0; X <= UB_X; X++) { WillReturn[X, Y] = IntArr[X]; } } return WillReturn; } }