AtCoderのARC
次のARCの問題へ
前のARCの問題へ
ARC049-B 高橋ノルム君
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("0 0 1");
WillReturn.Add("10 10 1");
//5.000000000000000
}
else if (InputPattern == "Input2") {
WillReturn.Add("2");
WillReturn.Add("0 0 1");
WillReturn.Add("10 10 2");
//6.666666666666667
}
else if (InputPattern == "Input3") {
WillReturn.Add("10");
WillReturn.Add("-27 -67 10");
WillReturn.Add("59 13 10");
WillReturn.Add("14 -15 9");
WillReturn.Add("-29 -84 7");
WillReturn.Add("-75 -2 2");
WillReturn.Add("-12 -74 5");
WillReturn.Add("77 31 9");
WillReturn.Add("40 64 8");
WillReturn.Add("-81 32 1");
WillReturn.Add("81 26 5");
//582.222222222222222
}
else if (InputPattern == "Input4") {
WillReturn.Add("8");
WillReturn.Add("-81739 73917 446");
WillReturn.Add("42230 30484 911");
WillReturn.Add("79354 -50126 200");
WillReturn.Add("33440 -47087 651");
WillReturn.Add("-73 84114 905");
WillReturn.Add("79222 -53608 713");
WillReturn.Add("65194 -46284 685");
WillReturn.Add("81145 40933 47");
//54924095.383189122374461
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
struct XYCInfoDef
{
internal double X;
internal double Y;
internal double C;
}
static List<XYCInfoDef> mXYCInfoList = new List<XYCInfoDef>();
static void Main()
{
List<string> InputList = GetInputList();
double[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => double.Parse(pX)).ToArray();
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
XYCInfoDef WillAdd;
WillAdd.X = wkArr[0];
WillAdd.Y = wkArr[1];
WillAdd.C = wkArr[2];
mXYCInfoList.Add(WillAdd);
}
double XCostMin = DeriveXCostMin();
double YCostMin = DeriveYCostMin();
var AnswerKouhoList = new List<double>();
AnswerKouhoList.Add(XCostMin);
AnswerKouhoList.Add(YCostMin);
Console.WriteLine(AnswerKouhoList.Max());
}
// 三分探索でX方向の移動の極小値を求める
static double DeriveXCostMin()
{
double L = mXYCInfoList.Min(pX => pX.X);
double R = mXYCInfoList.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 = DeriveXCost(C1);
double C2Val = DeriveXCost(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(DeriveXCost(L));
MinKouhoList.Add(DeriveXCost(R));
return MinKouhoList.Min();
}
// X座標を引数として、必要時間の最大値を返す
static double DeriveXCost(double pBaseX)
{
double WillReturn = double.MinValue;
foreach (XYCInfoDef EachXYCInfo in mXYCInfoList) {
double CurrCost = EachXYCInfo.C * Math.Abs(pBaseX - EachXYCInfo.X);
WillReturn = Math.Max(WillReturn, CurrCost);
}
return WillReturn;
}
// 三分探索でY方向の移動の極小値を求める
static double DeriveYCostMin()
{
double L = mXYCInfoList.Min(pX => pX.Y);
double R = mXYCInfoList.Max(pX => pX.Y);
var PairHashSet = new HashSet<string>();
while (L + double.Epsilon < R) {
double C1 = (L * 2 + R) / 3;
double C2 = (L + R * 2) / 3;
double C1Val = DeriveYCost(C1);
double C2Val = DeriveYCost(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(DeriveYCost(L));
MinKouhoList.Add(DeriveYCost(R));
return MinKouhoList.Min();
}
// Y座標を引数として、必要時間の最大値を返す
static double DeriveYCost(double pBaseY)
{
double WillReturn = double.MinValue;
foreach (XYCInfoDef EachXYCInfo in mXYCInfoList) {
double CurrCost = EachXYCInfo.C * Math.Abs(pBaseY - EachXYCInfo.Y);
WillReturn = Math.Max(WillReturn, CurrCost);
}
return WillReturn;
}
}
解説
C * max(X座標の差 , Y座標の差)
の最大値を最小化にしたいので
X座標の差の最大値を最小化しつつ
Y座標の差の最大値を最小化したものは
解の一つとなります。
数式に着目すれば、
X座標の最小値からX座標の最大値の区間で極小値を持つと分かるので
三分探索で解けます。