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つだけ持つので
三分探索を使ってます。