トップページに戻る    次のC#のサンプルへ    前のC#のサンプルへ

Problem79 パスコードの導出

問題

オンラインバンクで通常使われるsecurity methodは,
パスコードからランダムに選んだ3文字をユーザーに要求するものである.

たとえば, パスコードが531278のとき, 2番目, 3番目, 5番目の文字を要求されるかもしれない.
このとき, 期待される答えは: 317 である.

テキストファイルには,ログインに成功した50回の試行が記録されている.

3つの文字が常に順番通りに要求されるとするとき,
テキストファイルを分析して, 可能なパスコードのなかで最も短いものを見つけよ.


ソース

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

class Program
{
    static List<string> mAcceptStrList = new List<string>();

    static void Main()
    {
        mAcceptStrList.Add("319");
        mAcceptStrList.Add("680");
        mAcceptStrList.Add("180");
        mAcceptStrList.Add("690");
        mAcceptStrList.Add("129");
        mAcceptStrList.Add("620");
        mAcceptStrList.Add("762");
        mAcceptStrList.Add("689");
        mAcceptStrList.Add("762");
        mAcceptStrList.Add("318");
        mAcceptStrList.Add("368");
        mAcceptStrList.Add("710");
        mAcceptStrList.Add("720");
        mAcceptStrList.Add("710");
        mAcceptStrList.Add("629");
        mAcceptStrList.Add("168");
        mAcceptStrList.Add("160");
        mAcceptStrList.Add("689");
        mAcceptStrList.Add("716");
        mAcceptStrList.Add("731");
        mAcceptStrList.Add("736");
        mAcceptStrList.Add("729");
        mAcceptStrList.Add("316");
        mAcceptStrList.Add("729");
        mAcceptStrList.Add("729");
        mAcceptStrList.Add("710");
        mAcceptStrList.Add("769");
        mAcceptStrList.Add("290");
        mAcceptStrList.Add("719");
        mAcceptStrList.Add("680");
        mAcceptStrList.Add("318");
        mAcceptStrList.Add("389");
        mAcceptStrList.Add("162");
        mAcceptStrList.Add("289");
        mAcceptStrList.Add("162");
        mAcceptStrList.Add("718");
        mAcceptStrList.Add("729");
        mAcceptStrList.Add("319");
        mAcceptStrList.Add("790");
        mAcceptStrList.Add("680");
        mAcceptStrList.Add("890");
        mAcceptStrList.Add("362");
        mAcceptStrList.Add("319");
        mAcceptStrList.Add("760");
        mAcceptStrList.Add("316");
        mAcceptStrList.Add("729");
        mAcceptStrList.Add("380");
        mAcceptStrList.Add("319");
        mAcceptStrList.Add("728");
        mAcceptStrList.Add("716");

        var AppearedCharSet = new HashSet<char>();
        mAcceptStrList.ForEach(X => AppearedCharSet.UnionWith(X));
        char[] AppearedCharArr = AppearedCharSet.ToArray();

        Console.WriteLine("登場している数字は、{0}通りです。", AppearedCharArr.Length);
        Console.WriteLine("解の長さ上限を、{0}として深さ優先探索します。", AppearedCharArr.Length);

        var Stk = new Stack<string>();
        foreach (char EachKouho in AppearedCharArr) {
            Stk.Push(EachKouho.ToString());
        }

        while (Stk.Count > 0) {
            string Popped = Stk.Pop();

            if (Popped.Length == AppearedCharArr.Length) {
                if (IsOKOrder(Popped)) {
                    Console.WriteLine("解は{0}", Popped);
                    break;
                }
                continue;
            }

            foreach (char EachKouho in AppearedCharArr) {
                Stk.Push(Popped + EachKouho.ToString());
            }
        }
    }

    static bool IsOKOrder(string pStr)
    {
        foreach (string EachAcceptStr in mAcceptStrList) {
            int I = 0;

            bool IsOK = false;
            for (int J = 0; J <= pStr.Length - 1; J++) {
                if (pStr[J] == EachAcceptStr[I]) {
                    if (++I > EachAcceptStr.Length - 1) {
                        IsOK = true;
                        break;
                    }
                }
            }
            if (IsOK == false) return false;
        }
        return true;
    }
}


実行結果

登場している数字は、8通りです。
解の長さ上限を、8として深さ優先探索します。
解は73162890


解説

登場している数字は8通りあり、
解の長さ上限を、8として深さ優先探索して、
見つかった解の長さが8なので題意を満たしてます :-)