トップページに戻る    次の競技プログラミングの問題へ    前の競技プログラミングの問題へ

川添さん問題11 プライム・ホッパー

■■■問題■■■

ある素数に対し、次の変換1と2のいずれかを適用し、新たな素数を作ります。

●変換1 :元の数の右または左に1〜9のいずれかの数字1つをつなげる。
         (例:2→23、13→139、3→13、29→229)
●変換2 :元の数の右端または左端の数字1つを取り除く。
         (元の数が2桁以上の場合のみ。
          例:31→3、673→67、23→3、673→73)

例えば 7→227、17→37 は有効な変換ではありません。
また 103→03 のように、先頭に0のつく数への変換はできません。

さて、素数pとq (p < q) が与えられたときに、
素数pから始めて、変換1または2によりq以下の素数を作るということを繰り返し行い、
最小の変換回数でqを作ることを考えましょう。

p=5,q=67 のときの一例を示します。計5回の変換で67に変換できます。
途中の数がいずれも67以下の素数であることに注意して下さい。
なお、必ずしも変換1と2の両方を行う必要はありません。

5 → 53 → 3 → 37 → 7 → 67

素数p,qに対し、pから始めて q を作るときの最小の変換回数を F(p, q) と定義します。
そのような作り方が存在しない場合は F(p, q) = -1と定義します。

例えば F(5, 67) = 5,F(3, 29) = 3,F(5, 541) = 10,F(3, 7)= -1 です。

標準入力から、半角空白区切りで素数 p, q (p < q かつ q <= 10万) が与えられます。
標準出力にF(n)の値を出力するプログラムを書いてください。


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("5 67");
            //5
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("3 29");
            //3
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("5 541");
            //10
        }
        else if (InputPattern == "Input4") {
            WillReturn.Add("3 7");
            //-1
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static HashSet<string> SosuuSet = new HashSet<string>();

    //エラトステネスの篩で上限以下の素数の配列を返す
    static void Eratosthenes(int pJyougen)
    {
        var IsSosuuArr = new System.Collections.BitArray(pJyougen + 1);
        for (int I = 2; I <= IsSosuuArr.Count - 1; I++) {
            IsSosuuArr[I] = true;
        }
        for (int I = 2; I * I <= IsSosuuArr.Count - 1; I++) {
            if (IsSosuuArr[I] == false) continue;
            for (int J = I * 2; J <= IsSosuuArr.Count - 1; J += I) {
                IsSosuuArr[J] = false;
            }
        }
        for (int I = 2; I <= IsSosuuArr.Count - 1; I++) {
            if (IsSosuuArr[I]) SosuuSet.Add(I.ToString());
        }
    }

    struct JyoutaiDef
    {
        internal string CurrStr;
        internal int Level;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();
        int[] wkArr = InputList[0].Split(' ').Select(X => int.Parse(X)).ToArray();

        int P = wkArr[0];
        int Q = wkArr[1];

        Eratosthenes(Q);

        var Que = new Queue<JyoutaiDef>();
        JyoutaiDef WillEnque;
        WillEnque.CurrStr = P.ToString();
        WillEnque.Level = 0;
        Que.Enqueue(WillEnque);

        int Answer = -1;

        var VisitedSet = new HashSet<string>();
        VisitedSet.Add(WillEnque.CurrStr);

        while (Que.Count > 0) {
            JyoutaiDef Dequeued = Que.Dequeue();

            if (Dequeued.CurrStr == Q.ToString()) {
                Answer = Dequeued.Level;
                break;
            }

            var ConvStrList = new List<string>();
            ConvStrList.AddRange(Conv1(Dequeued.CurrStr));
            ConvStrList.AddRange(Conv2(Dequeued.CurrStr));

            foreach (string EachConvStr in ConvStrList) {
                if (VisitedSet.Add(EachConvStr) == false)
                    continue;

                WillEnque.CurrStr = EachConvStr;
                WillEnque.Level = Dequeued.Level + 1;
                Que.Enqueue(WillEnque);
            }
        }
        Console.WriteLine(Answer);
    }

    //変換1を行った結果のListを返す
    static string[] Conv1(string pBase)
    {
        var WillRerurn = new List<string>();
        for (char I = '1'; I <= '9'; I++) {
            WillRerurn.Add(pBase + I);
            WillRerurn.Add(I + pBase);
        }
        WillRerurn.RemoveAll(X => SosuuSet.Contains(X)==false);
        return WillRerurn.ToArray();
    }

    //変換2を行った結果のListを返す
    static string[] Conv2(string pBase)
    {
        var WillRerurn = new List<string>();
        int wkLen = pBase.Length;
        if (wkLen > 0) {
            WillRerurn.Add(pBase.Substring(1));
            WillRerurn.Add(pBase.Substring(0, wkLen - 1));
        }
        WillRerurn.RemoveAll(X => SosuuSet.Contains(X) == false);
        return WillRerurn.ToArray();
    }
}


解説

幅優先探索で解いてます。