AtCoderのABC    次のABCの問題へ    前のABCの問題へ

ABC191-C Digital Graffiti


問題へのリンク


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 5");
            WillReturn.Add(".....");
            WillReturn.Add(".###.");
            WillReturn.Add(".###.");
            WillReturn.Add(".###.");
            WillReturn.Add(".....");
            //4
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static char[,] mBanArr;
    static int UB_X;
    static int UB_Y;

    struct VectorInfoDef
    {
        internal int X1;
        internal int Y1;
        internal int X2;
        internal int Y2;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();

        mBanArr = CreateBanArr(InputList.Skip(1));
        UB_X = mBanArr.GetUpperBound(0);
        UB_Y = mBanArr.GetUpperBound(1);

        // 盤面の外周のベクトルのList
        var VectorInfoList = DeriveGaisyuuVectorList();

        // 内積が0のベクトルのペアの数が解
        long Answer = 0;
        for (int I = 0; I <= VectorInfoList.Count - 1; I++) {
            for (int J = I + 1; J <= VectorInfoList.Count - 1; J++) {
                // 単位ベクトルなので、始点と終点の少なくとも1点が一致してれば交点あり
                if (HasKouten(VectorInfoList[I], VectorInfoList[J]) == false) {
                    continue;
                }

                if (DeriveDot(VectorInfoList[I], VectorInfoList[J]) == 0) {
                    Answer++;
                }
            }
        }
        Console.WriteLine(Answer);
    }

    // ベクトル同士が交点を持つかを判定
    static bool HasKouten(VectorInfoDef pVect1, VectorInfoDef pVect2)
    {
        if (pVect1.X1 == pVect2.X1 && pVect1.Y1 == pVect2.Y1) return true;
        if (pVect1.X1 == pVect2.X1 && pVect1.Y2 == pVect2.Y2) return true;
        if (pVect1.X2 == pVect2.X2 && pVect1.Y1 == pVect2.Y1) return true;
        if (pVect1.X2 == pVect2.X2 && pVect1.Y2 == pVect2.Y2) return true;
        return false;
    }

    // ベクトル同士の内積を求める
    static long DeriveDot(VectorInfoDef pVect1, VectorInfoDef pVect2)
    {
        long DiffX1 = pVect1.X1 - pVect1.X2;
        long DiffY1 = pVect1.Y1 - pVect1.Y2;
        long DiffX2 = pVect2.X1 - pVect2.X2;
        long DiffY2 = pVect2.Y1 - pVect2.Y2;
        return DiffX1 * DiffX2 + DiffY1 * DiffY2;
    }

    // 盤面の外周のベクトルのListを返す
    static List<VectorInfoDef> DeriveGaisyuuVectorList()
    {
        var WillReturn = new List<VectorInfoDef>();

        Func<int, int, bool> IsGaisyuuFunc = (pX, pY) =>
        {
            if (pX < 0 || UB_X < pX) return true;
            if (pY < 0 || UB_Y < pY) return true;

            return mBanArr[pX, pY] == '.';
        };

        for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
            for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
                if (mBanArr[LoopX, LoopY] != '#') continue;

                // 4方向のチェック
                if (IsGaisyuuFunc(LoopX, LoopY - 1)) {
                    WillReturn.Add(
                        new VectorInfoDef() { X1 = LoopX, Y1 = LoopY, X2 = LoopX + 1, Y2 = LoopY });
                }
                if (IsGaisyuuFunc(LoopX, LoopY + 1)) {
                    WillReturn.Add(
                        new VectorInfoDef() { X1 = LoopX, Y1 = LoopY + 1, X2 = LoopX + 1, Y2 = LoopY + 1 });
                }

                if (IsGaisyuuFunc(LoopX - 1, LoopY)) {
                    WillReturn.Add(
                        new VectorInfoDef() { X1 = LoopX, Y1 = LoopY, X2 = LoopX, Y2 = LoopY + 1 });
                }
                if (IsGaisyuuFunc(LoopX + 1, LoopY)) {
                    WillReturn.Add(
                        new VectorInfoDef() { X1 = LoopX + 1, Y1 = LoopY, X2 = LoopX + 1, Y2 = LoopY + 1 });
                }
            }
        }
        return WillReturn;
    }

    ////////////////////////////////////////////////////////////////
    // IEnumerable<string>をcharの2次元配列に設定する
    ////////////////////////////////////////////////////////////////
    static char[,] CreateBanArr(IEnumerable<string> pStrEnum)
    {
        var StrList = pStrEnum.ToList();
        if (StrList.Count == 0) {
            return new char[0, 0];
        }
        int UB_X = StrList[0].Length - 1;
        int UB_Y = StrList.Count - 1;

        char[,] WillReturn = new char[UB_X + 1, UB_Y + 1];

        for (int Y = 0; Y <= UB_Y; Y++) {
            for (int X = 0; X <= UB_X; X++) {
                WillReturn[X, Y] = StrList[Y][X];
            }
        }
        return WillReturn;
    }
}


解説

□□□□□
□■■■□
□□■□□
□□□□□

という盤面で考えると
外周の単位ベクトルを列挙して、
交点を持つベクトル同士で、
内積が0の、ベクトルのペア数が解だと分かります。