Круги, разделяющие плоскость


23

задача

Вам будет дан набор окружностей на плоскости с центрами на прямой y = 0 . Гарантируется, что ни одна пара окружностей не имеет более одной общей точки.

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

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


Вот пример:

пример 1

С левой стороны вы видите круги, нарисованные в плоскости. Тем не менее, в правой половине изображения области, созданные кругами, окрашены отчетливо (по одному цвету на область). В этом примере шесть регионов.


вход

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

NКаждая из следующих строк содержит два целых числа x i и r i > 0 , представляющих окружность с центром (x i , 0) и радиусом r i .

Гарантируется, что ни одна пара окружностей не имеет более одной общей точки. Кроме того, гарантируется, что x i и r i не превышают 10^9по абсолютной величине (поэтому они удобно вписываются в 32-разрядное целое число).


Вход может быть:

  • читать из STDIN

  • читать из файла с именем Iв текущем каталоге

В качестве альтернативы вход может быть:

  • доступный как строка (включая переводы строки) в глобальной переменной

  • в стеке


Выход

Это должно быть одно целое число, количество произведенных регионов. Это должно быть записано в STDOUT или файл с именем Oв текущем каталоге.


правила

  • Самый короткий код в байтах выигрывает

  • + 200 байт, если ваш код не имеет полинома времени выполнения + сложность пространства в n

  • Бонус -100 байт для наихудшего ожидаемого времени выполнения + сложность пространства O(n log n)

  • Бонус -50 байт для наихудшего ожидаемого времени выполнения + сложность пространства O(n)

  • Бонус -100 байт для детерминированной среды выполнения + сложность пространства O(n)

При оценке времени выполнения:

  • Предположим, что у хеш-таблиц O(1)ожидаемое время выполнения для вставки, удаления и поиска независимо от последовательности операций и входных данных. Это может или не может быть правдой, в зависимости от того, использует ли реализация рандомизацию.

  • Предположим, что встроенная сортировка вашего языка программирования занимает детерминированное O(n log n)время, где nразмер входной последовательности.

  • Предположим, что арифметические операции над входными числами занимают только O(1)время.

  • Не предполагайте, что входные числа связаны константой, хотя, по практическим причинам, они есть. Это означает, что алгоритмы, такие как сортировка по основанию или сортировка по счету, не являются линейным временем. В общем, следует избегать очень больших постоянных факторов.


Примеры

Входные данные:

2 
1 3
5 1

Выход: 3


Входные данные:

3
2 2
1 1
3 1

Выход: 5

4
7 5
-9 11
11 9
0 20

Входные данные:

9
38 14
-60 40
73 19
0 100
98 2
-15 5
39 15
-38 62
94 2

Выход: 11


Советы

Мы можем использовать следующую идею для очень компактного решения. Давайте пересечем набор окружностей с осью X и интерпретируем точки пересечения как узлы на плоском графе:

введите описание изображения здесь

Каждый круг создает в этом графе ровно 2 ребра и до двух узлов. Мы можем подсчитать количество узлов, используя хеш-таблицу, чтобы отслеживать общее количество различных левых или правых границ.

Тогда мы можем использовать характеристическую формулу Эйлера для вычисления количества граней чертежа графа:

V - E + F - C = 1

F = E - V + C + 1

Чтобы вычислить Cколичество подключенных компонентов, мы можем использовать поиск в глубину .


Примечание. Эта проблемная идея заимствована из недавнего конкурса хорватских программистов , но, пожалуйста, не читайте, читая обзор решения. :)


Некоторые из этих бонусов приманки?
user2357112 поддерживает Monica

@ user2357112 Не думай, что это невозможно сделать, пока ты не докажешь;)
Никлас Б.

Ну, с входными данными, которые гарантированно помещаются в целое число машины, мы могли бы использовать сортировку по основанию и назвать ее O (n). Я ненавижу предполагать ограниченный размер входных данных, потому что, строго говоря, это означает, что существует конечное число возможных входных данных.
user2357112 поддерживает Monica

@ user2357112 Нет, я сказал, что вы не можете предполагать, что целые числа ограничены при оценке асимптотики, поэтому ни сортировка по осям, ни сортировка не будут линейными по времени и пространству. То, что они вписываются в слово, просто делает арифметику «реальной» O (1) и по практическим соображениям (ограниченная переменная ширина в большинстве языков)
Никлас Б.

@NiklasB. если у меня есть алгоритм, в котором единственным компонентом со сверхлинейной сложностью является сортировка, мне нужно реализовать сортировку слиянием, если мой язык использует быструю сортировку, чтобы получить n log nбонус? Также у меня есть новое концептуально новое решение. Должен ли я опубликовать новый ответ или заменить старый? (Я бы предпочел первое, если мое новое решение на самом деле не верное)
Мартин Эндер,

Ответы:


2

Mathematica, 125 122 - 150 = -28 символов

Я не знаю сложности встроенной функции ConnectedComponents.

1+{-1,2,1}.Length/@{VertexList@#,EdgeList@#,ConnectedComponents@#}&@Graph[(+##)<->(#-#2)&@@@Rest@ImportString[#,"Table"]]&

Использование:

1+{-1,2,1}.Length/@{VertexList@#,EdgeList@#,ConnectedComponents@#}&@Graph[(+##)<->(#-#2)&@@@Rest@ImportString[#,"Table"]]&[
"9
38 14
-60 40
73 19
0 100
98 2
-15 5
39 15
-38 62
94 2"]

11


Я думаю, что мы можем с уверенностью предположить, что ConnectedComponentsимеет линейную ожидаемую сложность наихудшего случая, поэтому, если есть O (n) компонентов, это было бы хорошо. Я не понимаю Mathematica, поэтому я не могу сказать, является ли это O (n) в целом и соответствует ли он бонусу -150? Я думаю, что это так. Я просто запускаю его с вводом в STDIN?
Никлас Б.

@NiklasB. его метод ввода просто передает строковую переменную анонимной функции. так что я думаю, что должно соответствовать требованиям. Что касается вывода, то в Mathematica это просто приведет к тому, что число окажется в выводе консоли, так что это, вероятно, тоже будет хорошо.
Мартин Эндер

Я проверил правильность этого, поэтому я считаю, что со счетом -28 это новый лидер. Поздравляем!
Никлас Б.

@NiklasB. почему только 150? Какая часть алгоритма имеет суперлинейную сложность в худшем случае?
Мартин Эндер

@ m.buettner 150 - для ожидаемого времени O (n). Для графиков с произвольными числами в качестве узлов, неявно определенных как здесь, вы просто не можете найти количество СС в линейном времени, что можно показать, уменьшив четкость элементов для связанных компонентов. Я думаю, что мы также можем уменьшить четкость элементов до исходной проблемы
Никлас Б.

4

Рубин - 312 306 285 273 269 259 символов

Этот ответ был заменен моим другим подходом, который использует значительно меньше символов и работает O(n log n).

Хорошо, идем. Для начала, я просто хотел рабочую реализацию, так что это еще не оптимизировано алгоритмически. Я сортирую круги от самых больших до самых маленьких и строю дерево (круги, включенные в другие круги, являются потомками этих более крупных). Обе операции идут O(n^2)в худшем и O(n log n)в лучшем случае. Затем я перебираю дерево для подсчета площадей. Если дочерние элементы круга заполняют весь его диаметр, появляются две новые области, в противном случае - только одна. Эту итерацию возьмите O(n). Так что у меня общая сложность O(n^2)и я не могу претендовать ни на награду, ни на штраф.

Этот код ожидает, что ввод без количества кружков будет сохранен в переменной s:

t=[]
s.lines.map{|x|x,r=x.split.map &:to_i;{d:2*r,l:x-r,c:[]}}.sort_by!{|c|-c[:d]}.map{|c|i=-1;n=t
while o=n[i+=1]
if 0>d=c[:l]-o[:l]
break
elsif o[:d]>d
n=o[:c]
i=-1
end
end
n[i,0]=c}
a=1
t.map &(b=->n{d=0
n[:c].each{|c|d+=c[:d]}.map &b
a+=d==n[:d]?2:1})
p a

Неуправляемая версия (ожидается ввод в переменной string):

list = []
string.split("\n").map { |x|
  m = x.split
  x,radius = m.map &:to_i
  list<<{x:x, d:2*radius, l:x-radius, r:x+radius, children:[]}
}
list.sort_by! { |circle| -circle[:d] }
tree = []
list.map { |circle|
  i = -1
  node = tree
  while c=node[i+=1]
    if circle[:x]<c[:l]
      break
    elsif circle[:x]<c[:r]
      node = c[:children]
      i = -1
    end
  end
  node[i,0] = circle
}
areas = 1
tree.map &(count = -> node {
  d = 0
  i = -1
  while c=node[:children][i+=1]
    count.call c
    d += c[:d]
  end
  areas += d == node[:d] ? 2 : 1
})
p areas

@NiklasB. да, этот тестовый пример был бы хорош. Отношение, которое определяет ребра в моем дереве - это просто включение одного круга в другой. Поскольку окружность не может содержаться в двух окружностях, которые не содержат друг друга (из-за условия «одного пересечения»), я не вижу, как это может быть DAG.
Мартин Эндер

Внуки узла тоже его дети?
user2357112 поддерживает Monica

@ user2357112 нет, потому что они могут разделить только своих прямых родителей
Мартин Эндер

@NiklasB. Если я приведу пример с вашим вопросом, я получу 11. За тот, что в вашем комментарии 9.
Мартин Эндер

@NiklasB. подождите, я на самом деле получаю 10и 8с моей версией без гольфа, но 11и 9с моей текущей версией игры в гольф: D
Мартин Эндер

2

Рубин, 203 183 173 133 - 100 = 33 символа

Так что здесь другой подход. На этот раз я сортирую круги по их самой левой точке. Круги, соприкасающиеся в самой левой точке, сортируются от наибольшего к наименьшему. Это требует O(n log n)(ну, Ruby использует быструю сортировку, так что на самом деле O(n^2)реализация сортировки слиянием / кучей, вероятно, выходит за рамки этой задачи). Затем я перебираю этот список, помня все крайние левые и крайние правые позиции кругов, которые я посетил. Это позволяет мне определить, соединяется ли серия кругов по всему большему кругу. В этом случае есть два подрайона, иначе только один. Эта итерация требует только O(n)полной сложности, O(n log n)которая дает право на вознаграждение в 100 символов.

Этот фрагмент ожидает, что входные данные будут предоставлены через файл в аргументах командной строки без количества кружков:

l,r={},{}
a=1
$<.map{|x|c,q=x.split.map &:to_r;[c-q,-2*q]}.sort.map{|x,y|a+=r[y=x-y]&&l[x]?2:1
l[y]=1 if l[x]&&!r[y]
l[x]=r[y]=1}
p a

Версия без поддержки (ожидает ввода в переменную string):

list = []
string.split("\n").map { |x|
  m = x.split
  x,radius = m.map &:to_r
  list<<{x:x, d:2*radius, l:x-radius, r:x+radius}
}
list.sort_by! { |circle| circle[:l] + 1/circle[:d] }
l,r={},{}
areas = 1
list.map { |circle|
  x,y=circle[:l],circle[:r]
  if l[x] && r[y]
    areas += 2
  else
    areas += 1
    l[y]=1 if l[x]
  end
  r[y]=1
  l[x]=1
}
p areas

К сожалению, это не подходит для всех больших тестовых случаев. Хотя это быстро;) У меня нет небольшого неудачного примера на этот раз, но вы можете найти тестовые данные на сайте конкурса, на который я ссылаюсь (это конкурс № 6)
Niklas B.

Первый неудачный тестовый пример - это kruznice / kruznice.in.2, который является первым «настоящим» тестовым примером, поэтому я предполагаю, что в алгоритме или реализации есть что-то принципиально неправильное. Правильно ли работает с произвольно вложенными кругами?
Никлас Б.

@NiklasB. спасибо, я посмотрю на тестовые случаи (хотя, возможно, до завтрашнего вечера я все исправлю)
Martin Ender

@NiklasB. Я понял, проблема и минимальный провал пример требует 5 кругов: -1 1 1 1 0 2 4 2 0 6. Я подумаю, как это исправить к завтрашнему вечеру (надеюсь).
Мартин Эндер

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

1

Юля - 260 -100 (бонус?) = 160

Интерпретируя окружности как фигуры с вершинами (пересечениями), ребрами и гранями (областями плоскости), мы можем связать друг друга, используя характеристику Эйлера , поэтому нам нужно только знать количество «вершин» и «ребер», чтобы иметь число «граней» или областей плоскости с формулой, написанной ниже:Эйлерова характеристика

ОБНОВЛЕНИЕ: Подумав некоторое время, я понял, что проблема с моим методом была только тогда, когда круги не связаны, поэтому у меня возникла идея, почему бы не соединить их искусственно? Таким образом, все будет удовлетворять формуле Эйлера.

Пример кругов

F = 2 + EV (V = 6, E = 9)

[Не работать с вложенными кругами, так что это не является решением проблемы для общих случаев]

Код :

s=readlines(open("s"))
n=int(s[1])
c=zeros(n,2)
t=[]
for i=1:n
    a=int(split(s[i+1]))
    c[i,1]=a[1]-a[2]
    c[i,2]=a[1]+a[2]
    if i==1 t=[c[1]]end
    append!(t,[c[i,1]:.5:c[i,2]])
end
e=0
t=sort(t)
for i in 1:(length(t)-1) e+=t[i+1]-t[i]>=1?1:0end #adds one edge for every gap
2+2n+e-length(unique(c)) # 2+E-V = 2+(2n+e)-#vertices

Я думаю, что ваша программа не удастся 2 -10 1 10 1.
Никлас Б.

«Гарантируется, что ни одна пара кругов не имеет более одной общей точки». так что я думаю, что это не будет применяться :)
CCP

@CCP У них ноль общих точек. n=2Круги (C=(-10,0), r=1)а(C=(10,0), r=1)
Никлас Б.

1
Разве график не должен быть связан, чтобы применить характеристику Эйлера?
user2357112 поддерживает Monica

1
Ах, вот простой случай: 4 0 2 1 1 10 2 11 1но я не думаю, что могу дать вам намного больше тестовых случаев, это было бы немного несправедливо
Никлас Б.

1

Spidermonkey JS, 308, 287 , 273 - 100 = 173

Я думаю, если бы я переписал это на Ruby или Python, я мог бы сохранить символы.

Код:

for(a=[d=readline],e={},u=d(n=1);u--;)[r,q]=d().split(' '),l=r-q,r-=-q,e[l]=e[l]||[0,0],e[r]=e[r]||[0,0],e[r][1]++,e[l][0]++
for(k=Object.keys(e).sort(function(a,b)b-a);i=k.pop();a.length&&a.pop()&a.push(0)){for([l,r]=e[i];r--;)n+=a.pop()
for(n+=l;l--;)a.push(l>0)}print(n)

Алгоритм:

n = 1 // this will be the total
e = {x:[numLeftBounds,numRightBounds]} // imagine this as the x axis with a count of zero-crossings
a = [] // this is the stack of circles around the "cursor".  
       // values will be 1 if that circle's never had alone time, else 0
k = sort keys of e on x
for each key in k: // this is the "cursor"
  n += key[numLeftBounds] // each circle that opens has at least one space.
  k[numRightBounds].times {n += a.pop()} // pop the closing circles. if any were never alone, add 1
  k[numLeftBounds].times {a.push(alwaysAlone)} // push the opening circles
  if !a.empty():
     set the innermost circle (top of stack) to false (not never alone)
  fi
loop

Я не очень хорош в больших обозначениях O, но я думаю, что это O (n), так как я эффективно перебираю каждый круг 3 раза (создать, слева, справа), а также сортирую ключи карты (и я сортирую по O ( п лог п) но это исчезает). Это детерминированный?


Если у кого-нибудь есть совет, как объединить rцикл и lцикл в одно утверждение, я был бы признателен.
Не то, чтобы Чарльз

Приветствия :) Похоже, ваша среда выполнения действительно O (n log n), из-за сортировки, которая будет -100. Я дам вам знать, прошел ли он все тестовые случаи.
Никлас Б.

Хорошо, ваша программа проходит все тестовые случаи с первой попытки. Я думаю, что что-то вроде этого (линия обзора с некоторым состоянием, поддерживаемым в стеке) было официальным решением от авторов проблемы. Ваша программа получает 173 баллов
Никлас Б.

@NiklasB. Благодарность!
Не то, чтобы Чарльз

Я пытался найти более надежное решение с перекрывающимися кругами ... потом я увидел, что они могут пересекаться только в одной точке.
Не то, чтобы Чарльз

-1

JavaScript (ES6) - 255 254 символов - 100 250 Бонус = 155 4

R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

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

R=/(\S+) (\S+)/ym;                  // Regular expression to find centre and width.
N=1;                                // Number of regions
w=l=0;                              // Maximum width and minimum left boundary.
X=[];                               // A 1-indexed array to contain the circles.
                                    // All the above are O(1)
for(;m=R.exec(S);){                 // For each circle
    X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};
                                    // Create an object with w (width), l (left boundary)
                                    // and r (right boundary) attributes.
    l=k<l?k:l;                      // Update the minimum left boundary.
    w=j<w?w:j                       // Update the maximum width.
}                                   // O(1) per iteration = O(N) total.
M=[];                               // An array.
X.map(x=>M[(x.l-l+1)*w-x.w]=x);     // Map the 1-indexed array of circles (X) to a
                                    // sparse array indexed so that the elements are
                                    // sorted by ascending left boundary then descending
                                    // width.
                                    // If there are N circles then only N elements are
                                    // created in the array and it can be treated as if it
                                    // is a hashmap (associative array) with a built in
                                    // ordering and as per the rules set in the question
                                    // is O(1) per insert so is O(N) total cost.
                                    // Since the array is sparse then it is still O(N)
                                    // total memory.
s=[];                               // An empty stack
i=0;                                // The number of circles on the stack.
M.map(x=>{                          // Loop through each circle
    while(i&&s[i-1][1]<x[1])        // Check to see if the current circle  is to the right
                                    // of the circles on the stack;
      N+=s[--i][0]?0:1;             // if so, decrement the length of the stack and if the
                                    // circle that pops off has radius equal to the total
                                    // radii of its children then increment the number of
                                    // regions by 1.

                                    // Since there can be at most N items on the stack then
                                    // there can be at most N items popped off the stack
                                    // over all the iterations; therefore this operation
                                    // has an O(N) total cost.
    i&&(s[i-1][0]-=x[0]);           // If there is a circle on the stack then this circle
                                    // is its child. Decrement the parent's radius by the
                                    // current child's radius.
                                    // O(1) per iteration
    s[i++]=x                        // Add the current circle to the stack.
  });
while(i)N+=s[--i][0]?0:1            // Finally, remove all the remaining circles from the
                                    // stack and if the circle that pops off has radius
                                    // equal to the total radii of its children then
                                    // increment the number of regions by 1.
                                    // Since there will always be at least one circle on the
                                    // stack then this has the added bonus of being the final
                                    // command so the value of N is printed to the console.
                                    // As per the previous comment on the complexity, there
                                    // can be at most N items on the stack so between this
                                    // and the iterations over the circles then there can only
                                    // be N items popped off the stack so the complexity of
                                    // all these tests on the circles on the stack is O(N).

Временная сложность теперь O (N).

Тестовый пример 1

S='2\n1 3\n5 1';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Выходы: 3

Тестовый пример 2

S='3\n2 2\n1 1\n3 1';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Выходы: 5

Тестовый пример 3

S='4\n7 5\n-9 11\n11 9\n0 20';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Выходы: 6

Тестовый пример 4

S='9\n38 14\n-60 40\n73 19\n0 100\n98 2\n-15 5\n39 15\n-38 62\n94 2';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Выходы: 11

Тестовый пример 5

S='87\n-730 4\n-836 2\n-889 1\n-913 15\n-883 5\n-908 8\n-507 77\n-922 2\n-786 2\n-782 2\n-762 22\n-776 2\n-781 3\n-913 3\n-830 2\n-756 4\n-970 30\n-755 5\n-494 506\n-854 4\n15 3\n-914 2\n-840 2\n-833 1\n-505 75\n-888 10\n-856 2\n-503 73\n-745 3\n-903 25\n-897 1\n-896 2\n-848 10\n-878 50\n-864 2\n0 1000\n-934 6\n-792 4\n-271 153\n-917 1\n-891 3\n-833 107\n-847 3\n-758 2\n-754 2\n-892 2\n-738 2\n-876 2\n-52 64\n-882 2\n-270 154\n-763 3\n-868 72\n-846 4\n-427 3\n-771 3\n-767 17\n-852 2\n-765 1\n-772 6\n-831 1\n-582 2\n-910 6\n-772 12\n-764 2\n-907 9\n-909 7\n-578 2\n-872 2\n-848 2\n-528 412\n-731 3\n-879 1\n-862 4\n-909 1\n16 4\n-779 1\n-654 68\n510 490\n-921 3\n-773 5\n-653 69\n-926 2\n-737 3\n-919 1\n-841 1\n-863 3';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Выходы: 105

Предыдущая версия

C=S.split('\n');N=1+C.shift()*1;s=[];C.map(x=>x.split(' ')).map(x=>[w=x[1]*1,x[i=0]*1+w]).sort((a,b)=>(c=a[1]-2*a[0])==(d=b[1]-2*b[0])?b[0]-a[0]:c-d).map(x=>{while(i&&s[i-1][1]<x[1])N+=s[--i][0]?0:1;i&&(s[i-1][0]-=x[0]);s[i++]=x});while(i)N+=s[--i][0]?0:1

С комментариями:

C=S.split('\n');                    // Split the input into an array on the newlines.
                                    // O(N)
N=1+C.shift()*1;                    // Remove the head of the array and store the value as
                                    // if there are N disjoint circles then there will be
                                    // N+1 regions.
                                    // At worst O(N) depending on how .shift() works.
s=[];                               // Initialise an empty stack.
                                    // O(1)
C .map(x=>x.split(' '))             // Split each line into an array of the two values.
                                    // O(1) per line = O(N) total.
  .map(x=>[w=x[1]*1,x[i=0]*1+w])    // Re-map the split values to an array storing the
                                    // radius and the right boundary.
                                    // O(1) per line = O(N) total.

  .sort((a,b)=>(c=a[1]-2*a[0])==(d=b[1]-2*b[0])?b[0]-a[0]:c-d)
                                    // Sort the circles on increasing left boundary and
                                    // then descending radius.
                                    // O(1) per comparison = O(N.log(N)) total.
  .map(x=>{                         // Loop through each circle
    while(i&&s[i-1][1]<x[1])        // Check to see if the current circle  is to the right
                                    // of the circles on the stack;
      N+=s[--i][0]?0:1;             // if so, decrement the length of the stack and if the
                                    // circle that pops off has radius equal to the total
                                    // radii of its children then increment the number of
                                    // regions by 1.

                                    // Since there can be at most N items on the stack then
                                    // there can be at most N items popped off the stack
                                    // over all the iterations; therefore this operation
                                    // has an O(N) total cost.
    i&&(s[i-1][0]-=x[0]);           // If there is a circle on the stack then this circle
                                    // is its child. Decrement the parent's radius by the
                                    // current child's radius.
                                    // O(1) per iteration
    s[i++]=x                        // Add the current circle to the stack.
  });
while(i)N+=s[--i][0]?0:1            // Finally, remove all the remaining circles from the
                                    // stack and if the circle that pops off has radius
                                    // equal to the total radii of its children then
                                    // increment the number of regions by 1.
                                    // Since there will always be at least one circle on the
                                    // stack then this has the added bonus of being the final
                                    // command so the value of N is printed to the console.
                                    // As per the previous comment on the complexity, there
                                    // can be at most N items on the stack so between this
                                    // and the iterations over the circles then there can only
                                    // be N items popped off the stack so the complexity of
                                    // all these tests on the circles on the stack is O(N).

Общая сложность по времени составляет O (N) для всего, кроме сортировки, которая является O (N.log (N)) - однако, если заменить ее на сортировку по сегментам, это уменьшит общую сложность до O (N).

Требуемая память O (N).

Угадайте, что будет дальше в моем списке задач ... сортировка ведра менее чем в 150 символах. Выполнено


Сортировка по группам имеет только среднюю сложность O(n)(на самом деле O(n+k)), но O(n^2)или O(n log n)худший случай, в зависимости от алгоритма сортировки, используемого внутри сегментов, поэтому вам нужно сделать это в 50 символов.
Мартин Эндер

@ m.buettner - Сортировка ведра может быть выполнена в O (N) сложности в худшем случае. Он основан на тщательном выборе сегментов и алгоритме O (1) для назначения блоков. Я делал это раньше (и доказал это), и мне просто нужно перенести код в JavaScript. Приведенный выше алгоритм уже является O (N.log (N)), поэтому единственным улучшением является получение алгоритма сортировки O (N).
MT0

Я был бы заинтересован в этом доказательстве и соответствующем выборе ведер. :)
Мартин Эндер

cs.princeton.edu/~dpd/Papers/SCG-09-invited/… (на странице 556) приводит пример сортировки ведра O (N). archive.org/stream/PlanarityTestingByPathAddition/… (стр. 75) дает пример O (N) комбинированного поиска в DFS и сортировки сегментов (временная сложность обсуждается на стр. 76).
MT0

1
@ Mt0, подожди, ты мог бы прочитать мое дополнение к разделу сложности вопроса. С неограниченными числами сортировка по линейному времени совершенно определенно невозможна
Никлас Б.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.