AtCoderのPAST    次のPASTの問題へ    前のPASTの問題へ

第7回PAST I ほくろ


問題へのリンク


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("2");
            WillReturn.Add("5 0");
            WillReturn.Add("-5 0");
            WillReturn.Add("-1 3");
            WillReturn.Add("2 4");
            //1 -3
            //-2 -4
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("4");
            WillReturn.Add("4 4");
            WillReturn.Add("12 10");
            WillReturn.Add("12 4");
            WillReturn.Add("8 7");
            WillReturn.Add("-4 -2");
            WillReturn.Add("100 10");
            //1.4 -4.8
            //0 0
            //-15 0
            //75.4 -52.8
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("10");
            WillReturn.Add("-40336 -25353");
            WillReturn.Add("25518 98473");
            WillReturn.Add("-66200 57666");
            WillReturn.Add("23235 -64774");
            WillReturn.Add("56870 -67151");
            WillReturn.Add("-99509 73639");
            WillReturn.Add("39965 -61027");
            WillReturn.Add("-54385 -34598");
            WillReturn.Add("-57063 14129");
            WillReturn.Add("63186 -88708");
            WillReturn.Add("88770 85106");
            WillReturn.Add("-92520 69200");
            //-8970.87249328212 61817.21737274555
            //-75079.28924877638 -74637.35403870217
            //-61384.55754506934 -105449.9760881721
            //-10508.55928227892 98726.04733711783
            //-63915.43362406853 -87648.93490309674
            //-84883.41976667292 8062.914405771756
            //-43119.58914921946 33307.21406245974
            //-77451.63868397648 -121148.543178062
            //88022.56926540422 -62121.98851386775
            //-11146.07084342446 90471.08392051774
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    struct ABInfoDef
    {
        internal double A;
        internal double B;
    }

    struct VectorDef
    {
        internal double X;
        internal double Y;
    }

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

        double[] wkArr = { };
        Action<string> SplitAct = pStr =>
            wkArr = pStr.Split(' ').Select(pX => double.Parse(pX)).ToArray();

        SplitAct(InputList[1]);
        double X1 = wkArr[0];
        double Y1 = wkArr[1];

        SplitAct(InputList[2]);
        double X2 = wkArr[0];
        double Y2 = wkArr[1];

        var ABInfoList = new List<ABInfoDef>();
        foreach (string EachStr in InputList.Skip(3)) {
            SplitAct(EachStr);
            ABInfoDef WillAdd;
            WillAdd.A = wkArr[0];
            WillAdd.B = wkArr[1];
            ABInfoList.Add(WillAdd);
        }

        // 両目の中点の座標
        VectorDef MidPos;
        MidPos.X = (X1 + X2) / 2;
        MidPos.Y = (Y1 + Y2) / 2;

        // 両目の中点が原点になるように、平行移動
        X1 -= MidPos.X;
        X2 -= MidPos.X;
        Y1 -= MidPos.Y;
        Y2 -= MidPos.Y;

        // Eを求める
        double E = Math.Sqrt(X1 * X1 + Y1 * Y1);

        double KaitenRad = DeriveKaitenRad(E, X2, Y2);

        // 逆回転に変換
        KaitenRad = Math.PI * 2 - KaitenRad;

        foreach (ABInfoDef EachABInfo in ABInfoList) {
            double X = EachABInfo.A;
            double Y = EachABInfo.B;

            X -= MidPos.X;
            Y -= MidPos.Y;

            VectorDef CurrPos;
            CurrPos.X = X;
            CurrPos.Y = Y;

            VectorDef Result = Exec1JiHenkan(CurrPos, Math.Sin(KaitenRad), Math.Cos(KaitenRad));
            decimal DecX = (decimal)Result.X;
            decimal DecY = (decimal)Result.Y;
            Console.WriteLine("{0} {1}", DecX, DecY);
        }
    }

    // (E,0)を何度回転したら(X2,Y2)になるかを返す
    static double DeriveKaitenRad(double pE, double pX2, double pY2)
    {
        // Y座標がマイナスなら、原点と対称移動
        bool Moved = false;
        if (pY2 < 0) {
            Moved = true;
            pX2 *= -1;
            pY2 *= -1;
        }

        double Rad = Math.Acos(pX2 / pE);

        // 原点と対称移動してたら、回転角を180度追加
        if (Moved) Rad += Math.PI;

        return Rad;
    }

    // ベクトルとSinとCosを引数として、回転したベクトルを返す
    static VectorDef Exec1JiHenkan(VectorDef pPos, double pSin, double pCos)
    {
        VectorDef WillReturn;
        WillReturn.X = pCos * pPos.X + pPos.Y * -pSin;
        WillReturn.Y = pSin * pPos.X + pPos.Y * pCos;
        return WillReturn;
    }
}


解説

下記の手順で解いてます。

手順01 両目の中点を求める
手順02 両目の中点が原点になるように平行移動
手順03 (E,0)が左目の位置なので回転角度をacosで求める
手順04 平行移動と回転角度が分かったので、平行移動と、一次変換を使った回転移動を行う