トップページに戻る    次の増井さんの書籍の問題へ    前の増井さんの書籍の問題へ

Q25 オシャレな靴ひもの結び方


C#のソース

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

class Program
{
    static void Main()
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();

        for (int I = 2; I <= 7; I++) {
            IEnumerable<int[]> PosYArrEnum = ExecDFS(I);

            Console.WriteLine("穴の数={0}での交点の最大数={1}",
                I, PosYArrEnum.Max(X => DeriveKoutenCnt(X)));
        }
        Console.WriteLine("経過時間={0}", sw.Elapsed);
    }

    struct JyoutaiDef
    {
        internal int Level;
        internal List<int> PosYList;
    }

    static IEnumerable<int[]> ExecDFS(int pAnaCnt)
    {
        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        WillPush.Level = 1;
        WillPush.PosYList = new List<int>() { 0 };
        stk.Push(WillPush);

        while (stk.Count > 0) {
            JyoutaiDef Popped = stk.Pop();

            //クリア判定
            if (Popped.Level == pAnaCnt * 2) {
                yield return Popped.PosYList.ToArray();
                continue;
            }

            WillPush.Level = Popped.Level + 1;

            //最後の穴は固定
            if (Popped.Level == pAnaCnt * 2 - 1) {
                WillPush.PosYList = new List<int>(Popped.PosYList) { 0 };
                stk.Push(WillPush);
                continue;
            }

            for (int I = 1; I <= pAnaCnt - 1; I++) {
                //使用済の穴は使用できない
                bool IsLeft = (Popped.Level % 2 == 0);
                bool WillContinue = false;
                for (int J = 0; J <= Popped.PosYList.Count - 1; J++) {
                    if (IsLeft && J % 2 == 1) continue;
                    if (IsLeft == false && J % 2 == 0) continue;
                    if (Popped.PosYList[J] == I) {
                        WillContinue = true;
                        break;
                    }
                }
                if (WillContinue) continue;

                WillPush.PosYList = new List<int>(Popped.PosYList) { I };
                stk.Push(WillPush);
            }
        }
    }

    struct MoveDef
    {
        internal int LeftPos;
        internal int RightPos;
    }

    //交点の数を求める
    static int DeriveKoutenCnt(int[] pPosYArr)
    {
        var MoveList = new List<MoveDef>();

        for (int I = 0; I + 1 <= pPosYArr.GetUpperBound(0); I++) {
            if (I % 2 == 0) {
                MoveList.Add(
                    new MoveDef() { LeftPos = pPosYArr[I], RightPos = pPosYArr[I + 1] });
            }
            else {
                MoveList.Add(
                    new MoveDef() { LeftPos = pPosYArr[I + 1], RightPos = pPosYArr[I] });
            }
        }

        int KoutenCnt = 0;
        for (int I = 0; I <= MoveList.Count - 1; I++) {
            for (int J = I + 1; J <= MoveList.Count - 1; J++) {
                if (MoveList[I].LeftPos > MoveList[J].LeftPos
                && MoveList[I].RightPos < MoveList[J].RightPos)
                    KoutenCnt++;
                if (MoveList[I].LeftPos < MoveList[J].LeftPos
                && MoveList[I].RightPos > MoveList[J].RightPos)
                    KoutenCnt++;
            }
        }
        return KoutenCnt;
    }
}


実行結果

穴の数=2での交点の最大数=1
穴の数=3での交点の最大数=6
穴の数=4での交点の最大数=15
穴の数=5での交点の最大数=28
穴の数=6での交点の最大数=45
穴の数=7での交点の最大数=66
経過時間=00:00:05.6278859


解説

線分の交差判定が難しかったです。