Поиск объединения промежутков

256
30 мая 2017, 02:40

Мне нужен именно алгоритм.

Есть веревка. Ее красят 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

Answer 1

На самом деле задача очень легко решается обычной (почти) сортировкой. Мы ВСЕ отрезки (начало и конец) сгружаем в общий массив, указав флаг начала или конца. Потом сортируем по координате. При этом рекомендую при равенстве сначала закрывающие элементы чтобы шли. Потом за 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) времени и памяти, используя сортировку подсчётом.

Answer 2

Извиняюсь за 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();
    }
}
READ ALSO
Критические секции. C++

Критические секции. C++

Здраствуйте, как правильно поставить критическую секцию в такой функции?

197
Header файлы и их проблема подключения

Header файлы и их проблема подключения

Работаю над проектом с компилятором MinGW32, компилирую в cmdexe и столкнулся с проблемой: Создал header-файл(UIClass

263
Помогите оптимизировать код

Помогите оптимизировать код

В задаче на вход программе дается количество невыполненных заданий и время, которого не хватает на решение этих заданий

258
Потоки. Приоритеты

Потоки. Приоритеты

Доброго времени сутокКакие потоки можно назвать фоновыми? Потоки с меньшим приоритетом можно назвать фоновыми относительно потока с большим...

270