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

Cマガ電脳クラブ(第150回) 正三角形はいくつ?

問題

Fig.1のように、正三角格子状に並んだ37個のドットがある。
この中に、3つのドットを結んでできる正三角形は何個あるだろうか。

たとえばFig.2には、4種類の大きさの正三角形が計15個ある。

          


ソース

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Solve(1);
        Solve(2);
    }

    static void Solve(int pQuestionNo)
    {
        //座標を設定
        if (pQuestionNo == 1) DerivePointArrQ1();
        else DerivePointArrQ2();

        int UB = mPointArr.GetUpperBound(0);

        int AnswerCnt = 0;
        for (int I = 0; I <= UB; I++) {
            for (int J = I + 1; J <= UB; J++) {
                for (int K = J + 1; K <= UB; K++) {
                    if (IsSeisankakukei(mPointArr[I], mPointArr[J], mPointArr[K]) == false)
                        continue;

                    Console.WriteLine("解{0}を発見", ++AnswerCnt);

                    if (pQuestionNo == 1) PrintAnswerQ1(I, J, K);
                    else PrintAnswerQ2(I, J, K);
                }
            }
        }
    }

    struct Point
    {
        internal int X;
        internal int YRoot3;
    }
    static Point[] mPointArr;

    //座標を設定(Q1用)
    static void DerivePointArrQ1()
    {
        var WillReturn = new List<Point>();
        WillReturn.Add(new Point() { X = 0, YRoot3 = 0 });

        for (int I = -1; I <= 1; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 1 });
        for (int I = -2; I <= 2; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 2 });
        for (int I = -3; I <= 3; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 3 });

        mPointArr = WillReturn.ToArray();
    }

    //座標を設定(Q2用)
    static void DerivePointArrQ2()
    {
        var WillReturn = new List<Point>();
        WillReturn.Add(new Point() { X = 0, YRoot3 = 0 });

        for (int I = -1; I <= 1; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 1 });
        for (int I = -6; I <= 6; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 2 });
        for (int I = -5; I <= 5; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 3 });
        for (int I = -4; I <= 4; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 4 });
        for (int I = -5; I <= 5; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 5 });
        for (int I = -6; I <= 6; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 6 });
        for (int I = -1; I <= 1; I += 2)
            WillReturn.Add(new Point() { X = I, YRoot3 = 7 });

        WillReturn.Add(new Point() { X = 0, YRoot3 = 8 });

        mPointArr = WillReturn.ToArray();
    }

    //座標3つを引数として正三角形かを判定
    static bool IsSeisankakukei(Point p1, Point p2, Point p3)
    {
        //三辺の長さが等しければ正三角形
        int Kyori1 = DeriveKyori2Jyou(p1, p2);
        int Kyori2 = DeriveKyori2Jyou(p1, p3);
        int Kyori3 = DeriveKyori2Jyou(p2, p3);

        if (Kyori1 != Kyori2) return false;
        if (Kyori1 != Kyori3) return false;

        return true;
    }

    //2点間の距離の2乗を求める
    static int DeriveKyori2Jyou(Point p1, Point p2)
    {
        int wkX = Math.Abs(p1.X - p2.X);
        int wkYRoot3 = Math.Abs(p1.YRoot3 - p2.YRoot3);

        return wkX * wkX + wkYRoot3 * wkYRoot3 * 3;
    }

    //解を出力(Q1用)
    static void PrintAnswerQ1(int p1, int p2, int p3)
    {
        var sb = new System.Text.StringBuilder();

        Func<int, char> wkFunc = pInt =>
            (pInt == p1 || pInt == p2 || pInt == p3) ? '●' : '・';

        sb.AppendFormat("   {0}", wkFunc(0));
        sb.AppendLine();
        sb.AppendFormat("  {0}{1}", wkFunc(1), wkFunc(2));
        sb.AppendLine();
        sb.AppendFormat(" {0}{1}{2}", wkFunc(3), wkFunc(4), wkFunc(5));
        sb.AppendLine();
        sb.AppendFormat("{0}{1}{2}{3}", wkFunc(6), wkFunc(7), wkFunc(8), wkFunc(9));
        sb.AppendLine();
        Console.WriteLine(sb.ToString());
    }

    //解を出力(Q2用)
    static void PrintAnswerQ2(int p1, int p2, int p3)
    {
        var sb = new System.Text.StringBuilder();

        Func<int, char> wkFunc = pInt =>
            (pInt == p1 || pInt == p2 || pInt == p3) ? '●' : '・';

        sb.AppendFormat("      {0}", wkFunc(0));
        sb.AppendLine();
        sb.AppendFormat("     {0}{1}", wkFunc(1), wkFunc(2));
        sb.AppendLine();

        for (int I = 3; I <= 9; I++) sb.Append(wkFunc(I));
        sb.AppendLine();

        sb.Append(" ");
        for (int I = 10; I <= 15; I++) sb.Append(wkFunc(I));
        sb.AppendLine();

        sb.Append("  ");
        for (int I = 16; I <= 20; I++) sb.Append(wkFunc(I));
        sb.AppendLine();

        sb.Append(" ");
        for (int I = 21; I <= 26; I++) sb.Append(wkFunc(I));
        sb.AppendLine();

        for (int I = 27; I <= 33; I++) sb.Append(wkFunc(I));
        sb.AppendLine();

        sb.AppendFormat("     {0}{1}", wkFunc(34), wkFunc(35));
        sb.AppendLine();
        sb.AppendFormat("      {0}", wkFunc(36));
        sb.AppendLine();
        Console.WriteLine(sb.ToString());
    }
}


実行結果

省略
解240を発見
      ・
     ・・
・・・・・・・
 ・・・・・・
  ・・・・・
 ・・・・・・
・・・・・・・
     ●●
      ●


解説

三辺の長さが等しい ⇔ 正三角形である
を使ってます。