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

第6回PAST J ポイントとコストと


問題へのリンク


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("3 2");
            WillReturn.Add("3 0");
            WillReturn.Add("3 1");
            WillReturn.Add("3 3");
            //6.000000000000000
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("2 100000");
            WillReturn.Add("-100000 100000");
            WillReturn.Add("-100000 100000");
            //0.000000000000000
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("13 -2");
            WillReturn.Add("3 -6");
            WillReturn.Add("-4 7");
            WillReturn.Add("-8 -8");
            WillReturn.Add("2 9");
            WillReturn.Add("1 -3");
            WillReturn.Add("0 4");
            WillReturn.Add("-6 6");
            WillReturn.Add("7 0");
            WillReturn.Add("1 0");
            WillReturn.Add("-9 7");
            WillReturn.Add("6 -1");
            WillReturn.Add("-7 -2");
            WillReturn.Add("5 6");
            //873.769230769230717
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static double mC;

    struct XYInfoDef
    {
        internal double X;
        internal double Y;
    }
    static List<XYInfoDef> mXYInfoList = new List<XYInfoDef>();

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

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

        SplitAct(InputList[0]);
        mC = wkArr[1];

        foreach (string EachStr in InputList.Skip(1)) {
            SplitAct(EachStr);
            XYInfoDef WillAdd;
            WillAdd.X = wkArr[0];
            WillAdd.Y = wkArr[1];
            mXYInfoList.Add(WillAdd);
        }
        double Result = ExecSanbuntansaku();
        Console.WriteLine(Result);
    }

    // 三分探索で極小値を求める
    static double ExecSanbuntansaku()
    {
        double L = mXYInfoList.Min(pX => pX.X);
        double R = mXYInfoList.Max(pX => pX.X);

        var PairHashSet = new HashSet<string>();
        while (L + double.Epsilon < R) {
            double C1 = (L * 2 + R) / 3;
            double C2 = (L + R * 2) / 3;

            double C1Val = DeriveCostSum(C1);
            double C2Val = DeriveCostSum(C2);

            if (C1Val < C2Val) {
                R = C2;
            }
            else {
                L = C1;
            }

            string Hash = string.Format("{0},{1}", L, R);
            if (PairHashSet.Add(Hash) == false) {
                break;
            }
        }

        var MinKouhoList = new List<double>();
        MinKouhoList.Add(DeriveCostSum(L));
        MinKouhoList.Add(DeriveCostSum(R));
        return MinKouhoList.Min();
    }

    // Pの値を引数として、コストのSumを返す
    static double DeriveCostSum(double pP)
    {
        double WillReturn = 0;
        foreach (XYInfoDef EachXYInfo in mXYInfoList) {
            double CurrCost1 = pP - EachXYInfo.X;
            double CurrCost2 = mC - EachXYInfo.Y;

            WillReturn += CurrCost1 * CurrCost1 + CurrCost2 * CurrCost2;
        }
        return WillReturn;
    }
}


解説

(C-Yi)^2 は定数なので
(P-Xi)^2 について考えます。

(P-Xi)^2 は、Pに関する2次関数の式で
これらの和は、2次関数になります。

下に凸な2次関数なので、極小値を1つだけ持つので
三分探索を使ってます。