using System; using System.Collections.Generic; using System.Linq; class Program { const int LimitN = 60; const int LimitLevel = 6; static void Main() { CreateFriendArrDict(); var AnswerKouhoList = new List<int[]>(); for (int LoopStaNum = 2; LoopStaNum <= LimitN; LoopStaNum++) { //素数なら除外 if (IsPrime(LoopStaNum)) continue; AnswerKouhoList.AddRange(ExecDFS(LoopStaNum)); } int AnswerN = AnswerKouhoList.Min(X => X.Max()); AnswerKouhoList.RemoveAll(A => Array.Exists(A, B => B > AnswerN)); Console.WriteLine("最小のN={0}", AnswerN); foreach (int[] EachArr in AnswerKouhoList) { Array.ForEach(EachArr, X => Console.Write("{0},", X)); Console.WriteLine(); } } //友達の配列のDictを作成 static Dictionary<int, List<int>> FriendArrDict = new Dictionary<int, List<int>>(); static void CreateFriendArrDict() { for (int I = 2; I <= LimitN; I++) { FriendArrDict[I] = new List<int>(); } for (int I = 2; I <= LimitN; I++) { for (int J = 2; J <= LimitN; J++) { if (I == J) continue; if (DeriveGCD(I, J) > 1) FriendArrDict[J].Add(I); } } //素数ならRemove foreach (int EachKey in FriendArrDict.Keys.ToArray()) { if (IsPrime(EachKey)) FriendArrDict.Remove(EachKey); else FriendArrDict[EachKey].RemoveAll(X => IsPrime(X)); } } //ユークリッドの互除法で2数の最大公約数を求める static int DeriveGCD(int pVal1, int pVal2) { int WarareruKazu = pVal2; int WaruKazu = pVal1; while (true) { int Amari = WarareruKazu % WaruKazu; if (Amari == 0) return WaruKazu; WarareruKazu = WaruKazu; WaruKazu = Amari; } } //試し割りで素数かを判定 static bool IsPrime(int pTarget) { if (pTarget == 2) return true; if (pTarget % 2 == 0) return false; for (int I = 3; I * I <= pTarget; I += 2) { if (pTarget % I == 0) return false; } return true; } struct JyoutaiDef { internal int Level; internal List<int> VisitedNumList; } //開始の数値を引数にして、探索し、解候補を返す static List<int[]> ExecDFS(int pStaNum) { var WillReturn = new List<int[]>(); var stk = new Stack<JyoutaiDef>(); JyoutaiDef WillPush; WillPush.Level = 0; WillPush.VisitedNumList = new List<int>() { pStaNum }; stk.Push(WillPush); while (stk.Count > 0) { JyoutaiDef Popped = stk.Pop(); //クリア判定 if (Popped.Level == LimitLevel) { WillReturn.Add(Popped.VisitedNumList.ToArray()); continue; } WillPush.Level = Popped.Level + 1; int CurrNum = Popped.VisitedNumList[Popped.Level]; foreach (int EachKouho in FriendArrDict[CurrNum]) { //再訪不可 if (Popped.VisitedNumList.Contains(EachKouho)) continue; //経路にショートカットが存在したら枝切り bool WillEdakiri = false; for (int J = 0; J <= Popped.Level - 1; J++) { int CheckNum = Popped.VisitedNumList[J]; if (FriendArrDict[CheckNum].BinarySearch(EachKouho) >= 0) { WillEdakiri = true; break; } } if (WillEdakiri) continue; WillPush.VisitedNumList = new List<int>(Popped.VisitedNumList); WillPush.VisitedNumList.Add(EachKouho); stk.Push(WillPush); } } return WillReturn; } }
最小のN=55 4,52,39,33,55,35,49, 4,34,51,33,55,35,49, 4,26,39,33,55,35,49, 8,52,39,33,55,35,49, 8,34,51,33,55,35,49, 8,26,39,33,55,35,49, 9,51,34,44,55,35,49, 省略
開始の数値ごとに深さ優先探索してます。 計算量削減で、経路にショートカットが存在したら枝切りしてます。