Задача с TopCoder Open 2019: разрезаем пирог на шесть частей

Задача с TopCoder Open 2019: разрезаем пирог на шесть частей
По следам «Наши победили: TopCoder Open 2019» публикую задачи с трека Algorithm (классическое спортивное программирование. За полтора часа нужно решить три задачи на Java, C#, C++ или Python.)

1. Пирог на шестерых

Постановка задачи

Лимит времени — 4 секунды.

У вас есть пирог. Если смотреть сверху, пирог имеет форму (строго) выпуклого многоугольника. Вам даны координаты вершин в целых числах X и Y.

У вас есть пять друзей. Вы хотите поделить пирог на шесть частей равной площади (но не обязательно одинаковой формы). Конечно же, любой может это сделать за пять разрезов, но только профи может сделать это за три разреза.

Найдите три разрезания прямыми линиями через одну точку, которые поделят пирог на шесть равных по площади частей. Выведите {x, y, d1, d2, d3}, где (x, y) — общая точка всех трёх разрезов, а d1, d2, d3 — углы направления разрезов в радианах.

DefinitionClass: CakeForSix
Method: cut
Parameters: int[], int[] Returns: double[] Method signature: double[] cut(int[] x, int[] y)
(be sure your method is public)

Примечания

  • Положительное направление вдоль оси х равно 0 (радиан), положительное направление вдоль оси y равно pi/2 (радиан).
  • Разрез в направлении d аналогичен разрезу в направлении pi*k+d для любого целого числа k.
  • Вы можете вывести любые направления, они не обязательно должны быть от [0, pi).
  • Грейдер вычислит площади ваших шести кусочков торта в doubles. Ответ будет принят, если относительная или абсолютная разница между ними меньше 10^(-4).
  • Точнее, пусть X и Y будут самыми маленькими и самыми большими из ваших шести областей, вычисленных грейдером. Тогда ваш ответ будет принят, если Y <max (X+10^(-4), X*1+10^(-4))).
  • (В первоначальной версии задачи использовалась точность 1e-7 вместо 1e-4. Для решения этой проблемы в архиве предел точности был снижен из-за наличия случаев вызова, которые, скорее всего, делают задачу неразрешимой с точностью 1e-7. В идеальном мире ограничения не допускают таких случаев и все еще требуют высокой точности, так что решить проблему с помощью некоторой общей числовой оптимизации непросто.)

Ограничения

  • x содержит от 3 до 50 элементов включительно.
  • y содержит столько же элементов, что и x.
  • все координаты между 0 и 10 000 включительно
  • x и y задают выпуклый многоугольник в направлении против часовой стрелки.

Оригинал на английском

Problem Statement

Time limit is 4 seconds.

You have a cake. Seen from above, the cake is a (strictly) convex polygon. You are given the coordinates of its vertices in the int[]s x and y.

You have five friends. You now want to cut the cake into six pieces of equal area (but not necessarily equal shape). Of course, anyone can do that in five cuts — but only a true pro can do it in three!

Find three straight-line cuts passing through the same point that cut the cake into six equally large parts. Return {x, y, d1, d2, d3}, where (x, y) is the common point of the three cuts, and d1, d2, d3 are their directions in radians.

Definition

Class: CakeForSix
Method: cut
Parameters: int[], int[] Returns: double[] Method signature: double[] cut(int[] x, int[] y)
(be sure your method is public)

Notes
— The positive direction along the x axis is 0 (radians), the positive direction along the y axis is pi/2 (radians).
— A cut in direction d is the same as a cut in direction pi*k+d for any integer k.
— You may return any directions, they do not have to be from [0,pi).
— The grader will compute the areas of your six cake pieces in doubles. The answer will be accepted if the relative or absolute difference between them is less than 10^(-4).
— More precisely, let X and Y be the smallest and the largest of your six areas, as computed by the grader. Then, your answer will be accepted if Y < max( X + 10^(-4), X * (1+10^(-4)) ).
— (The original version of the problem used 1e-7 precision instead of 1e-4. For upsolving this problem in the archive the precision limit was lowered due to the existence of challenge cases that most likely make the task unsolvable with 1e-7 precision. In an ideal world the constraints would not allow such cases and still require high precision, so that it isn’t easy to solve the problem via some general numeric optimization.)

Constraints
— x will have between 3 and 50 elements, inclusive.
— y will have the same number of elements as x.
— All coordinates will be between 0 and 10,000, inclusive.
— x and y will describe a convex polygon in counterclockwise order.

Примеры

0)

{0, 20, 30, 50, 30, 20}
{10, 0, 0, 10, 20, 20}
Returns:
{24.999999999437453, 9.999999999500002, 0.0, 0.7266423406817211, 2.4149503129080787 }

Симметричный, но не правильный шестиугольник. Пример ответа соответствует разрезанию его пополам по горизонтали и выполнению двух других разрезов по центру, которые разделяют каждую часть на три части.

Задача с TopCoder Open 2019: разрезаем пирог на шесть частей

1)

{0, 1000, 0}
{0, 0, 1000}
Returns:
{333.3333333331763, 333.3333333332546, 0.7853981633986264, 2.0344439357948154, 2.6779450445891753 }

Прямоугольный треугольник. Опять же, мы можем начать с одного из трех разрезов вдоль оси симметрии.

Задача с TopCoder Open 2019: разрезаем пирог на шесть частей

2)

{40, 70, 90, 90, 50}
{30, 20, 40, 100, 60}
Returns:
{69.79517771922892, 52.77575974637605, 2.0616329654335885, 3.637826104091601, 4.32123485812475 }

Неправильный пятиугольник.

Задача с TopCoder Open 2019: разрезаем пирог на шесть частей

3)

{300, 400, 300, 200}
{500, 600, 700, 600}
Returns: {299.99999999974995, 599.9999999995, 0.0, 1.107148717794088, 2.034443935795705 }

Квадрат, повернутый на 45 градусов.

Задача с TopCoder Open 2019: разрезаем пирог на шесть частей

[Источник]

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Я решил задачу за

  • менее чем за 10 минут

  • 10-30 минут

  • 30-60 минут

  • 1-2 часа

  • более чем за 2 часа

  • другое

Проголосовали 42 пользователя. Воздержались 47 пользователей.

Источник: habr.com