Суммарная длина это как найти

Время на прочтение
4 мин

Количество просмотров 11K

К нам в техподдержку часто приходит вопрос: «Как посчитать суммы длин отрезков (участков трубопровода, элементов электрических схем и т.п.) в чертеже?». Существует масса способов решения этой задачи, в сегодняшней публикации мы рассмотрим реализацию приложения на MultiCAD.NET API, суммирующего длины, которое работает в nanoCAD, AutoCAD и ZWCAD. В качестве примера мы возьмем задачу определения суммарной длины труб в схеме водоснабжения и рассмотрим два варианта выбора элементов для подсчета: пользовательский и по созданному фильтру.

Определение суммы длин отрезков, выбранных пользователем

Прежде чем приступить к определению длины отрезка, необходимо определить, что же такое отрезок в MultiCAD.NET. Отрезок является стандартным примитивом наряду с окружностью, текстом, сплайном и др. Для представления отрезка в базе данных чертежа используется класс DbLine из пространства имен всех примитивов Multicad.DatabaseServices.StandardObjects.

Объекты DbLine в качестве свойств содержат начальную и конечную точку, но не содержат информации о длине отрезка. Конечно, координат точек отрезка достаточно для вычисления его длины, но удобнее будет использовать его геометрическое представление — объект класса LineSeg3d (доступ к которому обеспечивает свойство DbLine.Line) и его свойство Length для получения длины:

double length = line.Line.Length;

Итак, рассмотрим первый вариант приложения, когда пользователю предлагается самостоятельно выбрать отрезки для вычисления итогового значения длины. Для реализации пользовательского выбора объекта будет использоваться метод SelectObjects класса менеджера объектов McObjectManager:

public static McObjectId[] SelectObjects(string sPromt);

Метод выводит подсказку в консоль и позволяет пользователю самому выбирать объекты, ID выбранных объектов записываются в массив. Затем производится распознавание элементов массива, и для объектов, которые являются отрезками, получаем длину и инкрементируем результат. Общий вид команды, реализующий эту процедуру:

CommandMethod("LineLengthSum", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
public void LineLengthSum()
{
  // Получаем объекты выбором на чертеже
  McObjectId[] idSelecteds = McObjectManager.SelectObjects("Выберите объекты типа линия");
  
  if (idSelecteds.Length == 0)
  {
    MessageBox.Show("Объекты не выбраны");
    return;
  }
  
  double lengthSum = 0;
  foreach (McObjectId currID in idSelecteds)
  {
    // Получаем объект по ID
    McObject currObj = currID.GetObject(); 
				
    // Распознавание типа объекта 
    if (currObj is DbLine)
    {
      lengthSum += (currObj as DbLine).Line.Length;
    }
  }

  MessageBox.Show(lengthSum.ToString(), "Длина всех выбранных отрезков:", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Кроме отрезков прямых на чертежах используются полилинии, которые представляют собой совокупность отрезков и/или дуговых элементов. Получить длину полилинии можно аналогично, использую геометрическое представление примитива — класс Polyline3d через свойство Polyline:

double length = polyline.Polyline.Length;

Автоматический подсчет суммарной длины линий

На практике, когда чертеж содержит большое число элементов и требуется исключить ошибки пользовательского ввода, объекты могут быть выбраны автоматически, используя фильтр объектов. При создании фильтра указываются необходимые критерии: область выбора объектов (листы, слои, документы, область, и пр.) и типы объектов.
Например, для того, чтобы выбрать все линии на конкретном слое используется фильтр с указанием имени слоя:

ObjectFilter filter = ObjectFilter.Create(true);
filter.AddLayer("Холодная вода");
filter.AddType(typeof(DbLine));
List<McObjectId> ids = filter.GetObjects();

Наиболее часто встречающийся на практике пример применения автоматического подсчета суммарной длины линий — формирование отчета по типу труб на схеме водоснабжения.

В нашем примере схема трубопровода организована таким образом, что трубы каждого типа расположены на отдельных слоях: «Контур 1» и «Контур 2».
Следующая команда формирует текстовый отчет с указанием всех типов труб, расположенных на отдельных слоях и их суммарной длины.

[CommandMethod("createReport", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
public void createReport()
{
  List<String> reportStrings = getLengthSumByLayer();
  if (reportStrings.Count == 0)
  {
    MessageBox.Show("Схема не содержит элементов линий и полилиний");
    return;
  }

  // Отступ для вывода строки отчета
  int indent = 0;

  // Заголовок отчета
  DbText caption = new DbText();
  caption.Text = new TextGeom("Длина труб по типу", new Point3d(0, indent, 0), Vector3d.XAxis, "Standard", 10);
  caption.DbEntity.AddToCurrentDocument();

  foreach (String str in reportStrings)
  {
    indent -= 10;
    DbText reportText = new DbText();
    reportText.Text = new TextGeom(str, new Point3d(0, indent, 0), Vector3d.XAxis, "Standard", 6);
    reportText.DbEntity.AddToCurrentDocument();
  }
}

Подсчет суммарной длины и заполнение строк отчета производится в методе getLengthSumByLayer(), код которого представлен ниже:

public List<String> getLengthSumByLayer()
{
  List<String> reportStrings = new List<String>();
      
  // Получаем все слои на чертеже
  List<string> layers = McObjectManager.CurrentStyle.GetLayers();
  foreach (string layerName in layers)
  {
    ObjectFilter filter = ObjectFilter.Create(true).AddType(typeof(DbLine)).AddType(typeof(DbPolyline)).AddLayer(layerName);
    List<McObjectId> idSelected = filter.GetObjects();
    if (idSelected.Count != 0)
    {
      double lengthSum = 0;
      foreach (McObjectId currID in idSelected)
      {
        // Получаем объект по ID
        McObject currObj = currID.GetObject();

        // Распознавание типа объекта 
        if (currObj is DbLine)
        {
          lengthSum += (currObj as DbLine).Line.Length;
        }
        else if (currObj is DbPolyline)
        {
          lengthSum += (currObj as DbPolyline).Polyline.Length;
        }
      }

      // Если суммарная длина отрезков и полилиний на слое ненулевая, то добавляем в текст отчета
      if (lengthSum != 0)
      {
        reportStrings.Add(layerName.ToString() + ": " + lengthSum.ToString());
      }
    }
  }
  return reportStrings;
}

После выполнения данной команды на чертеж будет добавлен отчет вида:

Подробную процедуру загрузки MultiCAD.NET приложений вы можете найти в нашей статье Пошаговый обзор: единое MultiCAD.NET приложение в nanoCAD, AutoCAD, ZWCAD.

Обсудить статью можно также и на нашем форуме.
Перевод статьи на английский: MultiCAD.NET: Calculating the total length of lines.

Суммарная длина

Cтраница 1

Суммарная длина по фронту в зависимости от мощности – от 1400 до 2400 мм, глубина – от 400 до 800 мм.
 [1]

Суммарная длина участков А.
 [2]

Суммарная длина L3 ( G) ребер, смежных только нефиксированным вершинам, которая определяется как суммарная длина ребер стандартного графа, построен-ногр на п – q вершинах, и оставшихся неучтенных ребер графа.
 [3]

Суммарная длина всех подпрограмм HIPACK составила на CDC-6500 5130 слов, в то время как решение задачи, связанной с заведением, заполнением и распечаткой одной одномерной и одной друхмерной гистограмм с использованием НВООК, эта система потребовала 11400 слов. Так как подпрограммы HIPACK независимы друг от друга, легко организовать их выполнение в оверлейном режиме, что позволит сократить объем требуемой памяти ЭВМ в несколько раз. Кроме того, в зависимости от вида решаемой задачи пользователь из пакета подпрограмм HIPACK может выбрать и использовать только те подпрограммы, которые ему нужны.
 [4]

Суммарная длина всех дефектов типа потеря металла составляет 833 098 м, что составляет 0 55 % протяженности обследованного участка трубопровода. Отсюда следует, что на болотах дефектов коррозии больше, чем на остальных участках.
 [6]

Суммарная длина горизонтальных участков труб должна быть не более 3 м, так как с увеличением их длины температура продуктов сгорания и величина тяги уменьшаются.
 [7]

Суммарная длина всех перпендикуляров, опущенных из любой точки, находящейся внутри равностороннего треугольника, на каждую из его сторон является величиной постоянной, равной его высоте.
 [9]

Суммарная длина трех отрезков, отсеченных на сторонах равностороннего треугольника прямыми, параллельными его сторонам, проведенными через любую точку внутри его, является величиной постоянной, равной длине стороны треугольника.
 [11]

Суммарная длина по фронту в зависимости от мощности – от 1400 до 2400 мм, глубина – от 400 до 800 мм.
 [12]

Суммарная длина светильников превышает длину помещения: необходимо или применить более мощные лампы ( у которых световой поток на единицу длины больше), или увеличить число рядов, или компоновать ряды из сдвоенных, строенных светильников.
 [13]

Суммарная длина светильников равна длине помещения: задача решается установкой непрерывного ряда светильников.
 [14]

Суммарная длина светильников меньше длины помещения: принимается ряд с равномерно распределенными вдоль него разрывами А, между светильниками.
 [15]

Страницы:  

   1

   2

   3

   4

   5

Отрезок, равный 40 см, разделён на четыре неравных отрезка. Расстояние между серединами крайних отрезков равно 28 см. Найдите расстояние между серединами средних отрезков в сантиметрах.

А я, как обычно, через переменные и уравнения. Обозначим отрезки k, l, m, n, расположенные в таком порядке. k и n – крайние отрезки. Сумма длин всех отрезков равна 40 см. Получаем уравнение:

k+l+m+n=40 (1)

Расстояние между серединами крайних отрезков, равное 28 см, составляют половины крайних отрезков и 2 средних. Получаем такое уравнение:

k/2+l+m+n/2=28 Домножим на 2, чтобы уйти от знаменателей.

k+2l+2m+n=56 (2)

Вычтем из (2) уравнения (1) уравнение. Получим:

l+m=16 см – Это длина двух средних отрезков вместе, а нам нужно найти расстояние между их серединами, оно будет составлять половину этой длины двух отрезков, то есть:

16/2=8 см.

Ответ: 8 см.

автор вопроса выбрал этот ответ лучшим

Лара Изюми­нка
[59.8K]

6 месяцев назад 

Попробуем разобраться в задаче.

Итак, известно, что весь отркзок 40. И состоит он из 4 неравных отрезков. ХУZW. Расстояние между серединами крайних отрезков известно, оно равно 28. Далее можно заметить, что 1/2хплюс у плюс z плюс 1/2 w равно 28. Тогда можем найти разницу между всем отрезком и этой известной его частью она будет равна 1/2х плюс 1/2 z=40-28=12. Тогда сумма отрезков крайних х и z будет равна в два раза больше, то есть 12*2=24. Тогда сумма средних отрезков равна 40-24=16. Тогда расстояние между их серединами будет равно их сумме поделенной на 2, то есть 16/2=8.

Ответ на эту задачку 8.

Nasos
[171K]

6 месяцев назад 

Поскольку расстояние между серединами крайних отрезков равно 28см, то по краям остаётся в сумме:

40см – 28см = 12см,

а это не что иное, как половина суммы длины обоих крайних отрезков, следовательно, из суммарная длина равна 24см, а тогда на суммарную длину двух средних отрезков приходится:

40см – 24см = 16см,

откуда не трудно посчитать, что расстояние между их серединами будет вдвое меньше, то есть 8см.

Груст­ный Родже­р
[396K]

6 месяцев назад 

Ну пусть расстояние от середины самого левого куска до левого конца отрезка х см. Тогда расстояние от середины самого правого куска до правого конца отрезка – 12-х см (12 – это 40-28). Значит, сумма длин двух крайних отрезков составляет 24 см. Тогда сумма длин двух средних – 16 см. И расстояние между их серединами – половина от этого, то есть 8 см.

Знаете ответ?

Смотрите также:

Что такое равновеликие фигуры (куб, квадрат, многоугольник)?

Для чего нужна математика, геометрия, физика в программировании?

Как отложить на данном луче от его начала отрезок, равный данному?

Как найти вписанный угол ACB, если дуга BC составляет 80 градусов?

Как найти длину отрезка BD, если SO = 35, SD = 37?

Как найти величину угла OAB, если угол OCD равен 30 градусам?

По каким учебникам изучают математику израильские школьники?

Как решить: В четырехугольнике АВСD противоположные стороны не параллельны?

Диагональ АС параллелограмма АВСD 21, от верш. В до диаг. 12. Чему равна S?

Как найти площадь треугольника ABM (см.)?

27 задание – ScanLine (сканирующая прямая)

Введение

Сейчас в базе заданий ЕГЭ задач на отрезки мало, но они вполне могут быть на экзамене. Для начала разберемся, что такое отрезки и с чем их едят?

Задачи на отрезки обычно описаны примерно так:

Вам дано множество отрезков:

  • найдите длину которую они суммарно занимают на прямой
  • найдите суммарную длину для нескольких видов отрезков на прямой
  • Сожмите множество, соединяя или удаляя некоторые отрезки, чтобы они покрывали ту же область на прямой
  • найдите максимальное количество отрезков, пересекающихся друг с другом на участке прямой(длины > 0)
  • найдите количество участков прямой, где пересекаются ровно X отрезков (где X натурально число)

Ещё 3 вида задач, которые маловероятны на ЕГЭ, но которые умеет решать ScanLine

  • найдите количество точек принадлежащих прямоугольнику с координатами x1, y1, x2, y2
  • найдите площадь поверхности, которую занимают множество прямоугольников
  • найдите максимальное количество пересекающихся отрезков на плоскости

Идея сканирующей прямой

Давайте представим каждый отрезок как пару точек: его начало и конец. После отсортируем наши точки,
чтобы по ним пробежаться “сканирующей прямой” и обработать.

segments = [(1, 10), (2, 5), (3, 15)]
points = []
for start, end in segments:
    points += [(start, 1)]  # 1  - начало отрезка
    points += [(end, -1)]   # -1 - конец отрезка
points.sort()  # [(1, 1), (2, 1), (3, 1), (5, -1), (10, -1), (15, -1)]
# Важное замечание по поводу сортировки, в НЕКОТОРЫХ случаях сортировать надо так,
# чтобы конец (-1) был перед началом (1). Но в каких-то задачах наоборот.
# Встроенная сортировка будет в случае (5, 1) и (5, -1) сортировать как [(5, -1), (5, 1)]

for point in points:
    pass  # сюда обработчик (сканирующая прямая)

Суммарная длина занимаемая всеми отрезками

Сформулируем задачу в формате ЕГЭ

Имеется набор данных, состоящий из отрезков лежащих на прямой (отрезок это пара целых чисел).
Вам требуется найти суммарную длину прямой, которую эти отрезки покрывают.
Гарантируется, что (ОТВЕТ В ЗАДАЧЕ ВЕРНЫЙ) в отрезках координата начала меньше координаты конца.
Программа должна напечатать одно число – длину, соответствующую условиям задачи.

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

Даны два входных файла (файл A и файл B),
каждый из которых содержит в первой строке количество пар N (1 ≤ N ≤ 1e6).
Каждая из следующих N строк содержит два натуральных числа в диапазоне
от -1e9 до 1e9 включительно.

Ввод Ответ
5
1 4
2 3
5 7
8 9
4 5 7

Пояснение к примеру
плохой интернет, проверьте подключение
Итоговая суммарная длинна равна 7-1 + 9-8 = 6 + 1 = 7

Для такой задачи метод сканирующей прямо как раз нам подходит!

with open("27.txt", "r") as file:
    n = int(file.readline())
    segments = [list(map(int, file.readline().split())) for _ in range(n)]

points = []
for start, end in segments:
    points += [(start, 1)]      # 1 - начало отрезка
    points += [(end, -1)]       # -1 - конец отрезка
points.sort()

amount_of_segments = 0          # нынешнее количество пересекающихся отрезков
length = 0                      # суммарная длинна
prev_p = 0                      # координаты последней точки

for p, t in points:             # координата точки и её тип (начало/конец)
    if amount_of_segments > 0:  # если хотя бы один отрезок есть
        length += p - prev_p    # добавляем разницу координат в длину
    prev_p = p
    amount_of_segments += t     # добавляем тип (смотри пояснения)

print(length)

Давайте разбираться что тут происходит!

  1. Мы ввели счётчик, который отвечает за количество пересекающихся отрезков на нашем промежутке. Он является ВАЖНОЙ деталью этого алгоритма
  2. Если счётчик больше 0, значит что у нас хотя бы один отрезок лежит на промежутке от prev_p до p, значит эту длину можно спокойно вносить в нашу сумму
  3. amount_of_segments += t, эта строка означает что если мы встретили начало отрезка, то мы увеличиваем счётчик отрезков на 1, а если встретили конец, то -1 (на 1 отрезок стало меньше). Именно по этому мы так поделили наши отрезки на (1 – начало), (-1 – конец).

Если основная идея ясна, идём дальше!

Суммарная длина нескольких видов отрезков

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

Значение S – это произведение этих найденных сумм.
Гарантируется, что (ОТВЕТ В ЗАДАЧЕ ВЕРНЫЙ) в отрезках координата начала меньше координаты конца.
Программа должна напечатать одно число – значение S.

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

Даны два входных файла (файл A и файл B),
каждый из которых содержит в первой строке количество троек N (1 ≤ N ≤ 1e6).
Каждая из следующих N строк содержит три натуральных числа в диапазоне
от -1e9 до 1e9 включительно.

Ввод Ответ
5
1 4 1
2 3 2
5 7 1
8 9 2
4 5 3 8

Пояснение к примеру
плохой интернет, проверьте подключение

Произведение – 8:

  • Суммарная длина типа1 (красных) – 4
  • Суммарная длина типа2 (зелёных) – 2
  • Суммарная длина типа3 (синих) – 1
from collections import defaultdict

with open("27.txt", "r") as file:
    n = int(file.readline())
    segments = [list(map(int, file.readline().split())) for _ in range(n)]
points = []
for start, end, color in segments:
    points += [(start, 1, color)]  # 1 - начало отрезка, ДОБАВЛЯЕМ ЦВЕТ так как он нам важен
    points += [(end, -1, color)]   # 1 - конец отрезка,  ДОБАВЛЯЕМ ЦВЕТ так как он нам важен
points.sort()

colors = []                        # стек где последний элемент - нынешний тип отрезка
color_length = defaultdict(int)    # словарь цвет-суммарная длина этого цвета
prev_p = 0                         # координаты последней точки
for p, t, c in points:             # координата, тип(начало/конец), цвет
    if colors:                     # если есть хотя бы один начавшийся и пока не закончившийся отрезок
        color_length[colors[-1]] += p - prev_p  # добавляем к сумме длин отрезков этого цвета промежуток от предыдущей точки до текущей
    prev_p = p

    if t == 1:                     # если текущая точка - начало отрезка
        colors.append(c)           # кладем его цвет на верх стека
    else:                          # если конец
        colors.pop()               # удаляем цвет с вершины стека(кстати, colors[-1] будет равен с, подумайте почему)

S = 1    # Считаем значение S
for key, val in color_length.items():
    S *= val
print(S)  # Выводим его

Идея очень похожа на решение задачи с одним типом отрезков:

  1. Заводим стек (если неясно что это, дайте знать, я опишу базовые структуры данных) типов. Почему именно стек? В контексте этого решения на вершине стека всегда будет лежать последний начавшийся отрезок. Этот отрезок можно легко “закончить”, сняв его с вершины стека.
  2. Заводим словарь, в котором будем хранить ответы тип:суммарная_длинна_этого_типа
  3. В случае если на стеке уже лежит хотя бы один цвет (if colors), прибавляем к ответу расстояние от начала предыдущего отрезка до текущей точки.
  4. Если текущая точка – начало отрезка, кладем его цвет на стек. Иначе – удаляем.

Я открыта для вопросов, так что если они возникли, пишите в группе или в личку

Сжатие множества отрезков

Имеется набор данных, состоящий из отрезков лежащих на прямой (отрезок это пара целых чисел).
Вам требуется переделать множество так, чтобы оно содержало в себе как можно меньше отрезков, но чтобы оно покрывало такие же промежутки прямой, что и оригинальное множество.
Гарантируется, что (ОТВЕТ В ЗАДАЧЕ ВЕРНЫЙ) в отрезках координата начала меньше координаты конца.
Программа должна напечатать одно число – размер минимального множества.

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

Даны два входных файла (файл A и файл B),
каждый из которых содержит в первой строке количество пар N (1 ≤ N ≤ 1e6).
Каждая из следующих N строк содержит два натуральных числа в диапазоне
от -1e9 до 1e9 включительно.

Ввод Ответ
5
1 4
2 3
5 7
8 9
4 5 2

Пояснение к примеру
плохой интернет, проверьте подключение
Мы можем переделать входные данные на множество размера 2 с отрезками: 1-7 и 8-9

Посмотрим как тут ScanLine может нам помочь:

with open("27.txt", "r") as file:
    n = int(file.readline())
    segments = [list(map(int, file.readline().split())) for _ in range(n)]
points = []
for start, end, color in segments:
    points += [(start, 1)]  # 1 - начало отрезка
    points += [(end, -1)]   # 1 - конец отрезка
points.sort(key=lambda a: [a[0], -a[1]])  # ВАЖНО, нам надо чтобы начало шло первее конца


compressed = []
amount_of_segments = 0
previous_start = 0
for p, t in points:
    if amount_of_segments == 0 and t == 1:   # если сейчас 0 отрезков, и появился новый
        previous_start = p                   # записываем новый старт
    if amount_of_segments == 1 and t == -1:      # если сейчас 1 отрезок, и мы встретили конец
        compressed.append([previous_start, p])   # добавляем сжатый отрезок в список
    amount_of_segments += t
print(len(compressed))

Важные моменты в этой идее:

  1. Нам нужно изменить сортировку точек. Это надо чтобы при пересечении отрезков в виде 1-4 4-6, у нас не обнулялся счётчик с количеством. Иначе в этом случае мы получим ответ не 1 (1-6), а 2 (1-4 и 4-6)
  2. compressed это список полученных сжатых отрезков. В данной задаче нам хранить сами отрезки необязательно, но если поменять условие на найдите колличество отрезков умноженное на длину максимального или что-то ещё сложнее. То наличие этого списка вам поможет легко решить любую модификацию.

Максимальное количество отрезков пересекающихся друг с другом

Имеется набор данных, состоящий из отрезков, лежащих на прямой (отрезок это пара целых чисел).
Вам требуется найти максимальное количество отрезков, которые пересекаются друг с другом (под пересечением имеется ввиду наложение отрезков, то-есть отрезки 1-4 4-5 не пересекаются, когда отрезки 1-4 3-5 пересекаются).
Гарантируется, что (ОТВЕТ В ЗАДАЧЕ ВЕРНЫЙ) в отрезках координата начала меньше координаты конца.
Программа должна напечатать одно число – искомое количество отрезков.

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

Даны два входных файла (файл A и файл B),
каждый из которых содержит в первой строке количество пар N (1 ≤ N ≤ 1e6).
Каждая из следующих N строк содержит два натуральных числа в диапазоне
от -1e9 до 1e9 включительно.

Ввод Ответ
5
1 4
2 4
5 7
8 9
3 5 3

Пояснение к примеру
плохой интернет, проверьте подключение
На промежутке 3-4 у нас пересекается аж 3 отрезка: 1-4, 2-4, 3-5

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

Попробуйте решить эту задачу самостоятельно.

Код решающий задачу

with open("27.txt", "r") as file:
    n = int(file.readline())
    segments = [list(map(int, file.readline().split())) for _ in range(n)]

points = []
for start, end in segments:
    points += [(start, 1)]  # 1 - начало отрезка
    points += [(end, -1)]  # -1 - конец отрезка
points.sort()

amount_of_segments = 0  # нынешнее количество пересекающихся отрезков
max_intersection = 0    # максимальное пересечение

for p, t in points:  # координата точки и её тип (начало/конец)
    # максимум среди нынешнего количества пересечения и максимального
    max_intersection = max(max_intersection, amount_of_segments) 
    amount_of_segments += t  # добавляем тип (смотри пояснения)

print(max_intersection)

Главная идея:

  1. Заменить счётчик суммы на максимальное пересечение

Количество отрезков, где пересекаются ровно X

Имеется набор данных, состоящий из отрезков лежащих на прямой (отрезок это пара целых чисел).
Вам требуется найти количество отрезков в исходном наборе, которые имеют пересечения с X и более другими отрезками (под пересечением имеет ввиду наложение отрезков, то-есть отрезки 1-4 4-5 не пересекаются, когда отрезки 1-4 3-5 пересекаются).
Гарантируется, что (ОТВЕТ В ЗАДАЧЕ ВЕРНЫЙ) в отрезках координата начала меньше координаты конца.
Программа должна напечатать одно число – искомое количество отрезков.

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

Даны два входных файла (файл A и файл B),
каждый из которых содержит в первой строке количество пар N (1 ≤ N ≤ 1e6) и число X (1 ≤ X ≤ N).
Каждая из следующих N строк содержит два натуральных числа в диапазоне
от -1e9 до 1e9 включительно.

Ввод Ответ
5 2
1 4
2 4
5 7
8 9
3 6 3

Пояснение к примеру
плохой интернет, проверьте подключение

  • Отрезок 1-4 пересекается с отрезками 2-4 и 3-6 (2 ≥ 2), поэтому он входит в наш ответ
  • Отрезок 2-4 пересекается с отрезками 1-4 и 3-6 (2 ≥ 2), поэтому он входит в наш ответ
  • Отрезок 3-6 пересекается с отрезками 1-4 и 2-4 (2 ≥ 2), поэтому он входит в наш ответ
  • Отрезок 5-7 пересекается ТОЛЬКО с 3-6 (1 < 2), поэтому он НЕ входит в наш ответ
  • Отрезок 8-9 не пересекается ни с чем (0 < 2), поэтому он НЕ входит в наш ответ

Это достаточно сложная задача. Её основная сложность в том, что если концы двух отрезков одинаковые,
то мы можем потерять какой-то отрезок из ответа (см. пример). Так что этот случай нужно обработать дополнительно или придумать какую-то более интересную идею…

with open("27/ScanLine/input_x_or_more.txt", "r") as file:
    n, x = map(int, file.readline().split())
    segments = [list(map(int, file.readline().split())) for _ in range(n)]

points = []
for i, (start, end) in enumerate(segments):  # давайте пронумеруем отрезки, чтобы их отличать друг от друга
    points += [(start, 1, i)]  # 1 - начало отрезка
    points += [(end, -1, i)]   # -1 - конец отрезка
points.sort()


answer = set()            # ответ (индексы отрезков которые имеют x или более пересечений)
current_segments = set()  # нынешние отрезки (которые сейчас открыты)
prev_p = 0

for p, t, i in points:  # координата точки, её тип (начало/конец) и индекс отрезка
    if len(current_segments) > x:  # если отрезок пересекается с x или более отрезками
        answer |= current_segments  # добавляем в ответ всё наше множество отрезков

    if t == 1:   # добавляем новый отрезок в список нынешних
        current_segments.add(i)
    if t == -1:  # удаляем отрезок из списка нынешних
        current_segments.remove(i)  

print(len(answer))

Главные идеи:

  1. Мы храним все индексы нынешних отрезков (и ответа) в set’е, чтобы у нас удалялись повторения

Заключение

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

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

Ресурсы

Если что-то было непонятно, советую изучить дополнительные ресурсы:

  • Очень советую эту статью от Tinkoff Generation для укрепления материала
  • Расширенная задача для “2D отрезков” на плоскости
    • Более простое объяснение алгоритма от ИТМО
  • БЕСПЛАТНЫЕ слитые курсы ЛКШ с задачами и разборами, прям советую решить для проверки знаний
  • Ещё задачи с тестирующей системой (HARD)

Контакты

  • Мой телеграм
  • Чат с будущими стобальниками

Отдельное спасибо редактору – Екатерине Максимовой <3

Страницы 1

Чтобы отправить ответ, вы должны войти или зарегистрироваться

#1 11 мая 2005г. 16:29:43

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Тема: Как найти общую длину всех выделенных отрезков?

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

#2 Ответ от Умник 11 мая 2005г. 17:04:36

  • Умник
  • Восстановленный участник
  • На форуме с 17 июня 2004г.
  • Сообщений: 206
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

не помню толи сам накарябал то ли на форуме срисовал используйте этот лисп:

(defun c:ln (/)
  (apply '+
     (mapcar '(lambda
            (x)
             (vlax-curve-getDistAtParam
               (vlax-ename->vla-object x)
               (vlax-curve-getEndParam x)
             )
          )
         (vl-remove-if
           'listp
           (mapcar 'cadr (ssnamex (ssget)))
         )
     )
  )
)

#3 Ответ от diz 11 мая 2005г. 17:15:13

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Большое спасибо. Только если честно, я ещё не профессионал и не знаю куда это писать. Но буду искать. Если не трудно подскажите

#4 Ответ от VK 11 мая 2005г. 19:51:13

  • VK
  • Восстановленный участник
  • На форуме с 8 июня 2002г.
  • Сообщений: 224
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

#5 Ответ от Евгений Елпанов 11 мая 2005г. 21:08:43

  • Евгений Елпанов
  • Евгений Елпанов
  • Активный участник
  • Откуда: Москва
  • На форуме с 2 июля 2004г.
  • Сообщений: 2,538
  • Спасибо: 10

Re: Как найти общую длину всех выделенных отрезков?

> Умник
Програмка отличная, но как-то непонятно:

(vlax-curve-getDistAtParam
(vlax-ename->vla-object x);вызов через  vla-obj
(vlax-curve-getEndParam x);вызов через ent-name
)

В хелпе сказано, обе эти функции вызывать через vla-obj
но

(vlax-curve-getDistAtParam
x                         ;вызов через ent-name
(vlax-curve-getEndParam x);вызов через ent-name
)

Тоже отлично работает…
Может ли кто-нибудь прокаментировать?

#6 Ответ от Евгений Елпанов 11 мая 2005г. 21:43:59

  • Евгений Елпанов
  • Евгений Елпанов
  • Активный участник
  • Откуда: Москва
  • На форуме с 2 июля 2004г.
  • Сообщений: 2,538
  • Спасибо: 10

Re: Как найти общую длину всех выделенных отрезков?

Попробовал запустить все vlax-curve с параметром ent-name
(car (entsel))
Все отработали без ошибок! Хотя хелп напоминает, что надо
(vlax-ename->vla-object (car (entsel)))
Интересно, это недокументированная возможность или…

#7 Ответ от diz 12 мая 2005г. 10:51:49

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Нашёл на подсказанной вами ссылке програмку
(vl-load-com)
(defun entLen ( / set:entities int:allEntities int:curveEntities int:l rea:length)
  (setq set:entities (ssget))
  (if set:entities
    (progn
      (setq int:allEntities (sslength set:entities)   ; количество выбранных примитивов
       int:curveEntities 0            ; счетчик линейных примитивов
       int:l 0               ; счетчик
       rea:length 0.0            ; общая длина линейных примитивов
      ) ;_  setq
      (while (< int:l (sslength set:entities))
   (if (not
         (vl-catch-all-error-p
      (vl-catch-all-apply
        ‘vlax-curve-getStartPoint
        (list (vlax-ename->vla-object (ssname set:entities int:l)))
      ) ;_  vl-catch-all-apply
         ) ;_  vl-catch-all-error-p
       ) ;_  not
     (setq   int:curveEntities (1+ int:curveEntities)
      rea:length     (+ rea:length
                 (vlax-curve-getDistAtParam
                   (vlax-ename->vla-object (ssname set:entities int:l))
                   (vlax-curve-getEndParam (ssname set:entities int:l))
                 ) ;_  vlax-curve-getDistAtParam
              ) ;_  +
     ) ;_  setq
   ) ;_  if
   (setq int:l (1+ int:l))
      ) ;_  while
      (princ (strcat “n Выбрано примитивов: ” (itoa int:allEntities)
           “, из них линейных: ” (itoa int:curveEntities)
           “n Общая длина линейных примитивов: ” (rtos rea:length)
           )
        )
    ) ;_  progn
    (alert “Примитивы не выбраны!”)
  ) ;_  if
(prin1)
) ;_  defun
Создал файл с расширением LSP
Загрузил приложение
После ввода в командную строку (entLen), следует предложение выбора объекта. Но после его выбора, хоть я нажимаю на Enter, хоть на првую кнопку мыши, всё сбрасывается.
Что делать?
P.S. Точно так же загружаю програмку подсказанную Умником, набираю c:ln и полное молчание.

#8 Ответ от Александр Ривилис 12 мая 2005г. 12:03:45

  • Александр Ривилис
  • Александр Ривилис
  • Активный участник
  • Откуда: Украина / Киев
  • На форуме с 15 апреля 2005г.
  • Сообщений: 8,661
  • Спасибо: 158

Re: Как найти общую длину всех выделенных отрезков?

Какая верисия AutoCAD?

#9 Ответ от diz 12 мая 2005г. 13:18:59

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

2005

#10 Ответ от diz 12 мая 2005г. 13:26:53

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Кстати, программа

(vl-load-com)
(defun entLen ( / set:entities int:allEntities int:curveEntities int:l rea:length)
  (setq set:entities (ssget))
  (if set:entities
    (progn
      (setq int:allEntities (sslength set:entities)   ; количество выбранных примитивов
       int:curveEntities 0            ; счетчик линейных примитивов
       int:l 0               ; счетчик
       rea:length 0.0            ; общая длина линейных примитивов
      ) ;_  setq
      (while (< int:l (sslength set:entities))
   (if (not
         (vl-catch-all-error-p
      (vl-catch-all-apply
        'vlax-curve-getStartPoint
        (list (vlax-ename->vla-object (ssname set:entities int:l)))
      ) ;_  vl-catch-all-apply
         ) ;_  vl-catch-all-error-p
       ) ;_  not
     (setq   int:curveEntities (1+ int:curveEntities)
      rea:length     (+ rea:length
                 (vlax-curve-getDistAtParam
                   (vlax-ename->vla-object (ssname set:entities int:l))
                   (vlax-curve-getEndParam (ssname set:entities int:l))
                 ) ;_  vlax-curve-getDistAtParam
              ) ;_  +
     ) ;_  setq
   ) ;_  if
   (setq int:l (1+ int:l))
      ) ;_  while
      (princ (strcat "n Выбрано примитивов: " (itoa int:allEntities)
           ", из них линейных: " (itoa int:curveEntities)
           "n Общая длина линейных примитивов: " (rtos rea:length)
           )
        )
    ) ;_  progn
    (alert "Примитивы не выбраны!")
  ) ;_  if
(prin1)
) ;_  defun

пошла без проблем. Большое спсибо “kos”-у

#11 Ответ от Владимир Громов 12 мая 2005г. 14:06:30

  • Владимир Громов
  • Активный участник
  • На форуме с 10 июля 2004г.
  • Сообщений: 8,349
  • Спасибо: 4

Re: Как найти общую длину всех выделенных отрезков?

Может, следует в последней программе заменить слово “примитив” на слово “объект”?

#12 Ответ от Александр Ривилис 12 мая 2005г. 14:28:29

  • Александр Ривилис
  • Александр Ривилис
  • Активный участник
  • Откуда: Украина / Киев
  • На форуме с 15 апреля 2005г.
  • Сообщений: 8,661
  • Спасибо: 158

Re: Как найти общую длину всех выделенных отрезков?

diz пишет:

P.S. Точно так же загружаю програмку подсказанную Умником, набираю c:ln и полное молчание.

Только сейчас до меня дошло! biggrin
В командной строке нужно было набирать ln, а не c:ln
А по поводу версии AutoCAD я спросил, т.к. в вериях до AutoCAD 2000 эти функции не работают.

#13 Ответ от diz 12 мая 2005г. 16:39:53

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Если набираю ln, то следует предложение выбора объекта. Но после его выбора, хоть я нажимаю на Enter, хоть на првую кнопку мыши, всё сбрасывается. Но всё таки лучше чем раньше

#14 Ответ от Fantomas 12 мая 2005г. 18:49:55

  • Fantomas
  • Восстановленный участник
  • На форуме с 7 декабря 2003г.
  • Сообщений: 392
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Мой вариант:

(defun c:elen(/ fList firSet entSet filOut entList totLen)
  (vl-load-com)
  (setq fList '((-4 . "<OR")(0 . "*LINE")
      (0 . "CIRCLE")(0 . "ARC")
      (0 . "ELLIPSE")(-4 . "OR>")
      (-4 . "<NOT")(0 . "MLINE")
      (-4 . "NOT>"))
   filOut 0
   ); end setq
  (if
    (not
      (and
   (setq firSet(ssget "_I")
         entSet(ssget "_I" fList)
         ); end setq
   ); end and
      ); end not
    (setq entSet(ssget fList))
    (setq filOut(-(sslength firSet)(sslength entset)))
    ); end if
  (if entSet
    (progn
      (setq entList
      (mapcar 'vlax-ename->vla-object
                    (vl-remove-if 'listp
                     (mapcar 'cadr(ssnamex entSet))))
       totLen
        (apply '+
          (mapcar '(lambda (x)
                (vlax-curve-getDistAtParam x
             (vlax-curve-getEndParam x)))
             entList); end mapcar
          ); end apply
       ); end setq
      (if(/= 0 filOut)
   (princ(strcat "n" (itoa filout)
            " were filtered out (unsupported type)"))
   ); end if
      (princ(strcat "nTotal entities: "(itoa(length entList))
          " Total length: "(rtos totLen)); end strcat
       ); end princ
      ); end progn
    (progn
        (if(/= 0 filOut)
   (princ(strcat "n" (itoa filout)
            " were filtered out (unsupported type)"))
   (princ "nNothing selected")
   ); end if
    ); end progn
    ); end if
      (princ)
      ); end c:elen 

#15 Ответ от Геннадий aka PG 12 мая 2005г. 20:13:00

  • Геннадий aka PG
  • Восстановленный участник
  • На форуме с 4 апреля 2002г.
  • Сообщений: 1,348
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Я поюзал первую функцию Умника– нормально работает для линий и дуг.

#16 Ответ от Евгений Елпанов 12 мая 2005г. 20:24:26

  • Евгений Елпанов
  • Евгений Елпанов
  • Активный участник
  • Откуда: Москва
  • На форуме с 2 июля 2004г.
  • Сообщений: 2,538
  • Спасибо: 10

Re: Как найти общую длину всех выделенных отрезков?

> diz
Вопрос, с которого надо было начинать…

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

У какого типа примитива ты смотришь длинну?
Что есть прогон – отрезок, полилиния, сплайн или может быть блок?

#17 Ответ от Александр Ривилис 12 мая 2005г. 21:25:16

  • Александр Ривилис
  • Александр Ривилис
  • Активный участник
  • Откуда: Украина / Киев
  • На форуме с 15 апреля 2005г.
  • Сообщений: 8,661
  • Спасибо: 158

Re: Как найти общую длину всех выделенных отрезков?

… или может быть твердое тело, мультилиния и т.д…

#18 Ответ от Евгений Елпанов 13 мая 2005г. 10:38:42

  • Евгений Елпанов
  • Евгений Елпанов
  • Активный участник
  • Откуда: Москва
  • На форуме с 2 июля 2004г.
  • Сообщений: 2,538
  • Спасибо: 10

Re: Как найти общую длину всех выделенных отрезков?

> Александр Ривилис
Твердое тело наврятли… У него не посмотришь длинну (или что-то выражающее длинну) в свойствах…
Хотя можно передавать в названии слоя или в названии цвета, но не думаю – тогда проще выделить и посмотреть на слой или цвет…
Скорее всего прогон – примитив не имеющий свойства окончания…

#19 Ответ от diz 13 мая 2005г. 10:39:42

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

Мне в основном нужно находить сумму длин прямых линий, и это хорошо выполнияется программой, которрую выложил kos (я писал об этом), но почему то все остальные предложенные программы не идут. Следует предложение выбора объекта, и после выбора хоть я жму на Enter, хоть на правую кнопку, всё сбрасывается. Просто интересно почему?
И ещё вопрос. Я создал кнопку для работающего лиспа, но после перезагрузки компьютера, что бы она работала нужно нужно каждый раз загружать этот лисп. Нельзя ли зделать так, что бы это происходило автоматически?

#20 Ответ от Умник 13 мая 2005г. 10:57:14

  • Умник
  • Восстановленный участник
  • На форуме с 17 июня 2004г.
  • Сообщений: 206
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

> diz
Я использую запосщенную приблуду на 2004 и на 2005 (англ. версии) все работает чудесно… У вас случаем в командной сторке сколько строчек – если 2 то результата видно не будет – надо увеличить количество строк до 3-х – результат выводиться в командную строку или воспользуйтесь такой прогой:

(defun c:ln (/)
  (alert
    (strcat "Total Length is "
        (rtos (apply '+
             (mapcar '(lambda
                    (x)
                     (vlax-curve-getDistAtParam
                       (vlax-ename->vla-object x)
                       (vlax-curve-getEndParam x)
                     )
                  )
                 (vl-remove-if
                   'listp
                   (mapcar 'cadr (ssnamex (ssget)))
                 )
             )
          )
          2
          2
        )
    )
  )
)

кстати говоря, если вы не использовали раньше лиспов то нужно дописать строчку:
(vl-load-com)
второй после defun
у меня подгружено больше двух сотен функций и загружать с каждой функцией (vl-load-com) смысла нет …

#21 Ответ от Александр Ривилис 13 мая 2005г. 11:28:28

  • Александр Ривилис
  • Александр Ривилис
  • Активный участник
  • Откуда: Украина / Киев
  • На форуме с 15 апреля 2005г.
  • Сообщений: 8,661
  • Спасибо: 158

Re: Как найти общую длину всех выделенных отрезков?

> diz
Чтобы не нужно было загружать вручную lsp-файл, впришите в макрос для кнопки:

^C^C^P(if (null entLen) (load "entlen.lsp")) (entlen) ^P

Подразумевается, что имя lsp-файла entlen.lsp и он находится в путях доступа AutoCAD.

#22 Ответ от diz 13 мая 2005г. 11:37:05

  • diz
  • Восстановленный участник
  • На форуме с 18 октября 2004г.
  • Сообщений: 107
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

У меня действительно была 1 строка в командной строке. Теперь всё получается. Всем большое спасибо!!!

#23 Ответ от Геннадий aka PG 13 мая 2005г. 11:37:05

  • Геннадий aka PG
  • Восстановленный участник
  • На форуме с 4 апреля 2002г.
  • Сообщений: 1,348
  • Спасибо: 0

Re: Как найти общую длину всех выделенных отрезков?

> diz

> Александр Ривилис
Лучше сделать свое отдельное меню (пусть даже пока из обной кнопки) и подгрузить егою
Подробнее
http://cadhlp.kulichki.com/pdmnu.htm
Посмотри там же сборник CADHLP там есть свое меню и в разделе Расчеты аналогичная прога, взятая тут

/*
https://www.caduser.ru/forum/topic11823.html
*/
(defun C:Dlina (/ Nab Sum i Curve Param)
 (vl-load-com)
     (if (setq Nab (ssget))
         (progn
               (setq Sum 0 i 0)
               (repeat (sslength Nab)
               (setq Curve (vlax-ename->vla-object (ssname Nab i))
                         i (1+ i)
               Param (vl-catch-all-apply 'vlax-curve-getEndParam
               (list Curve))
    )
    (if (not (vl-catch-all-error-p Param))
        (setq Sum (+ Sum (vlax-curve-getDistAtParam Curve Param)))
)
)
)
)
(princ (strcat "nСумма длин выбранных элементов равна: " (rtos Sum 2 2)))
(prin1)
)

Страницы 1

Чтобы отправить ответ, вы должны войти или зарегистрироваться

Добавить комментарий