Мне нужен именно алгоритм.
Есть веревка. Ее красят N человек. Каждый может покрасить разное количество промежутков. Найти те промежутки, которые были покрашены N раз. Один человек не может покрасить один и тот же участок несколько раз.
Входные данные:
В первой строке N количество людей, которые красят верёвку. В следующих строках:
M количество промежутков, котрые покрасил человек.
Далее промежутки веревки (координаты начала и конца), которые был покрашены этим человеком.
Например:
2
1 30 80
2 30 40 160 165
Ответ: 10
3
1 30 80
2 0 20 50 90
2 750 795 972 982
Ответ: 0
На самом деле задача очень легко решается обычной (почти) сортировкой. Мы ВСЕ отрезки (начало и конец) сгружаем в общий массив, указав флаг начала или конца. Потом сортируем по координате. При этом рекомендую при равенстве сначала закрывающие элементы чтобы шли. Потом за 1 проход поддерживая число открытых отрезков. Ну и ответ просто сложить. Примерный код:
vector < pair<int, int> > point;
int main(){
int N,M;
cin >> N;
for (int i=0; i < N; i++){
cin >> M;
for (int j=0;j < M;j++){
int x,y;
cin >> x >> y;
point.push_back( make_pair(x,-1) );
point.push_back( make_pair(y, 1) );
}
}
sort (point.begin(), point.end() );
int open = 0;
int sum = 0;
int prev = 0;
for (auto x : point){
if (open == N)
sum += x.first - prev;
open -= x.second;
if (open == N)
prev = x.first;
}
cout << sum;
}
Запускаемый пример
Если вдруг нужен максимальный фрагмент, то нужно изменить 1 строку (сумму на максимум).
Сложность O(L log L) время, O(L) память. Где L - сумма по всем M. При малых ограничениях на длину можно редуцировать до O(Z) времени и памяти, используя сортировку подсчётом.
Извиняюсь за C#
- С++
не умею.
// Это структура, представляющая один отрезок
struct Segment
{
public int Start;
public int End;
public int Length => End - Start;
// Ищет пересечение двух отрезков и возвращает его или null если отрезки не пересекаются
public static Segment? Intersection(Segment seg1, Segment seg2)
{
int Min(int x, int y) => x < y ? x : y;
int Max(int x, int y) => x > y ? x : y;
int start = Max(seg1.Start, seg2.Start);
int end = Min(seg1.End, seg2.End);
if (end < start) return null;
return new Segment { Start = start, End = end };
}
}
class Program
{
static void Main(string[] args)
{
// Ввод данных
int n = int.Parse(Console.ReadLine());
Segment[][] segments = new Segment[n][];
for (int i = 0; i < n; ++i)
{
string[] parts = Console.ReadLine().Split();
int m = int.Parse(parts[0]);
segments[i] = new Segment[m];
for (int j = 0; j < m; ++j)
segments[i][j] = new Segment { Start = int.Parse(parts[2 * j + 1]), End = int.Parse(parts[2 * j + 2]) };
}
// Собственно сам алгоритм
// Коллекция текущих отрезков - отрезки, которые покрасили каждый из людей с номерами [0, i]
List<Segment> painted = segments[0].ToList();
for (int i = 1; i < n; ++i)
{
// Здесь будем копить пересечения из painted и отрезков, покрашенных i-м человеком
List<Segment> intersect = new List<Segment>();
foreach (var seg1 in segments[i])
foreach (var seg2 in painted)
{
var s = Segment.Intersection(seg1, seg2);
if (s != null) intersect.Add((Segment)s);
}
// Заменяем коллекцию текущих на пересечения
painted = intersect;
// Если на каком-то шаге у нас уже нет пересечений - досрочный выход
if (intersect.Count == 0) break;
}
// Вывод результатов
if (painted.Count == 0)
Console.WriteLine(0);
else
Console.WriteLine(painted.Max(s => s.Length));
Console.ReadLine();
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Здраствуйте, как правильно поставить критическую секцию в такой функции?
Работаю над проектом с компилятором MinGW32, компилирую в cmdexe и столкнулся с проблемой: Создал header-файл(UIClass
В задаче на вход программе дается количество невыполненных заданий и время, которого не хватает на решение этих заданий
Доброго времени сутокКакие потоки можно назвать фоновыми? Потоки с меньшим приоритетом можно назвать фоновыми относительно потока с большим...