61 / 5 / 1
Регистрация: 03.06.2013
Сообщений: 354
Записей в блоге: 3
1

Как ускорить логику цикла? [for experts]

25.01.2021, 16:21. Показов 4574. Ответов 62

Author24 — интернет-сервис помощи студентам
Приветсвую.
Есть рабочий код для простой задачи. На входе имеем начало и конец отрезкОВ надо определить какие области эти отрезки НЕ перекрыли. Грубо говоря какие доски забора остались НЕ покрашены.
Например
C
1
2
3
4
5
6
7
8
9
На входе:
10 //длина забора
2 //сколько отрезков
1 4 //начало конец отрезка
5 6 //начало конец отрезка
На выходе:
0 1
4 5
6 10
Вот сама программа
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
 
int main()
{
    int L, start = -1, count = 0;
    scanf("%d", &L);
    unsigned int *fence = (int *)calloc((L >> 5) + 1, sizeof(int)); //set memory to 0
    if (!fence) perror("calloc failed");
 
    int N;
    scanf("%d", &N);
    for (int i = 0; i < N; i++) {
        int st; //starting point
        int ed; //ending point
        scanf("%d%d", &st, &ed);
        
        // for (int i = st; i < ed; i++) fence[i] = 1;
        for (int i = st; i < ed; i++) fence[i>>5] |= (1 << (i & 31));
 
    }
    
    for (int i = 0; i < L; i++) {
 
        if (!fence[i>>5] && ((i + 32) < L)) {
            if (count == 0) {start = i; printf ("%d ",i);}
            count += 32; i += 31; continue;
        }
        else {
 
            // if ((fence[i] || i+1 == L) && count > 0)
            if (fence[i>>5] & (1 << (i & 31))) {
                if (count > 0) {printf ("%d\n",start+count); count = 0;}
            }
            else {
                if (count == 0) {start = i; printf ("%d ",i);}
                count++;
            }
        }
    }
    
    if (count > 0) printf ("%d\n",start+count);
    if (start < 0) puts("All painted");
    free (fence);
 
    return 0;
}

//битовое расположение используется для уменьшения памяти (отведенно максимум 2Гб для нашей задачи) и (надеюсь) увеличения скорости


Но стоит задача его "ускорить". Т.к. например с такими входными данными этот код делается неприемлимо долго
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
2000000000 //Длина
72 //Отрезки
51 57
566 4234
598149 834729
5122 6160
17 46
165271503 259311575
288436131 1932691397
75 78
343 393
41 45
204 479
74 92
207 490
49 56
964644464 1887812645
136 420
429742458 1053501121
195 393
232 1608
184 6763
13 33
60169371 1162580884
774423404 797664100
1381580035 1668522412
190444 284746
112880052 1389027745
196 279
117760 859558
121381 236758
40 83
51 74
4048 6191
32 82
1 65
37 148
0 73
591646 893422
224008 649271
3150 8259
951966787 1627123054
318604 604539
81 97
781864601 1390933683
17 124
1030908877 1796833002
39 45
82739 363091
2571 3239
156 333
4930 7479
996706325 1268325988
19 90
26667 108371
52581129 803126065
1833231690 1908070559
783093028 807124796
154115 347846
1731 6452
12 78
3 33
462351 1805485861
271 460
1282262829 1424278575
5787 8055
3759 4011
87992 288855
245938 797316
3128 7514
42 80
398695717 864069801
43 44
1223 3675


Жду от уважаемого сообщества один из двух варианта ответа
А) как еще можно ускорить данную логику ?
Б) если существенно ускорения выше обозначенной логики не возможно, подскажите алгоритм (словесный код) как можно быстро (всмысле не написать код быстро а чтоб программа быстро крутилась) решить данную задачу ?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.01.2021, 16:21
Ответы с готовыми решениями:

Как ускорить работу цикла?
Всем привет. Итак, мне нужно было решить задачу на подобии вот этой...

Как ускорить выполнение цикла
Есть ajax запрос по которой передается данные в другой файл и там выполняется цикл от 100 до 1000...

Как ускорить выполнение цикла на Update
имеется код на выполнение обновления базы из грида по кнопке, но все дело в том что таблица имеет...

Можно ли как нибудь ускорить работу цикла for?
Подскажите пожалуйста - можно ли как нибудь ускорить работу цикла for? Заранее сильно благодарен!

62
2817 / 2325 / 703
Регистрация: 29.06.2020
Сообщений: 8,577
25.01.2021, 16:34 2
Цитата Сообщение от alexbmd Посмотреть сообщение
и (надеюсь) увеличения скорости
На больших объемах битовые операции сильно загрузят проц.
Никогда не писали кодирование файлов ?
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
25.01.2021, 16:37 3
Отсортируйте список отрезков по их левому концу. Повторяйте до посинения цикл "Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки. Иначе переходи к Б и начинай сначала". На выходе получите массив не пересекающихся отрезков, отсортированных по их расположению на заборе. Оставшаяся часть элементарна.
1
61 / 5 / 1
Регистрация: 03.06.2013
Сообщений: 354
Записей в блоге: 3
25.01.2021, 16:39  [ТС] 4
SmallEvil, не писал.
0
2817 / 2325 / 703
Регистрация: 29.06.2020
Сообщений: 8,577
25.01.2021, 16:41 5
Если отрезки идут упорядоченно , и ввод не с клавиатуры,не то и массив не нужен.
пример посл:
20
3
1-5
7-9
19-20
0
61 / 5 / 1
Регистрация: 03.06.2013
Сообщений: 354
Записей в блоге: 3
25.01.2021, 16:51  [ТС] 6
SmallEvil, отрезки идут в перемешку... возможно и перекрытие и накрытие

Добавлено через 3 минуты
Цитата Сообщение от Renji Посмотреть сообщение
Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки
это всмысле если правый край больше ?
а как быть если
А 5-10
Б 8-15
?

я понимаю что надо объеденить до 5-15 но я про то что вроде как одного вашего условия нехватает для всех случаев или я туплю
0
6091 / 3449 / 1402
Регистрация: 07.02.2019
Сообщений: 8,768
25.01.2021, 16:57 7
alexbmd, похожая задача(одна из многих на отрезки), описание решения там есть, нужно только подправить алгоритм.
Игнорируйте отрезок
2
2817 / 2325 / 703
Регистрация: 29.06.2020
Сообщений: 8,577
25.01.2021, 17:49 8
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <sstream>
#include <map>
 
using namespace std;
 
void scanSeq(istream & is, ostream & os)
{
    map<int, int> intervs;
    size_t L, N;
    int from, to;
    is>>L;
    is>>N;
    
    for (size_t i = 0; i<N; ++i)
    {
        is>>from>>to;
        intervs[from]=to;
    }
 
    int pos_b = 0, pos_e;
    for (auto i : intervs)
    {
        pos_e = i.first;
        if (pos_e>pos_b)
           os<<pos_b<<" "<<pos_e<<endl;
        pos_b = i.second;
    }
    if (pos_b < L)
        os<<pos_b<<" "<<L<<endl;
}
int main()
{
    stringstream ss;
    ss<<10<<endl<<3<<endl<<"5 6"<<endl<<"1 2"<<endl<<"7 9";
    scanSeq(ss, cout);
}
Добавлено через 27 секунд
map сразу сортирует, что плюс

Добавлено через 1 минуту
минус что проверяет абсолютно все интервалы, можно еще доработать

Добавлено через 2 минуты
Цитата Сообщение от alexbmd Посмотреть сообщение
А 5-10
Б 8-15
ммда, надо доработать ...

Добавлено через 7 минут
проблема только в подпоследовательностях
например , ss<<10<<endl<<3<<endl<<"5 6"<<endl<<"1 2"<<endl<<"4 9";
5 6 входит в 4 9, с кандачка не идет. подумать надо

Добавлено через 10 минут
при добавлении в map придется таки объединять последовательности ...

исправил обьединением последовательносте при формировании map
прошу протестировать
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//g++  7.4.0
#include <iostream>
#include <sstream>
#include <map>
 
using namespace std;
 
void scanSeq(istream & is, ostream & os)
{
    map<int, int> intervs;
    int L, N;
    int from, to;
    is>>L;
    is>>N;
     map<int, int>::iterator it;   
    for (int i = 0; i<N; ++i)
    {
        is>>from>>to;
        if ( (it= intervs.upper_bound(from)) != intervs.end())
            if (it->second < to)
            {
               it->second = to;
               continue;
            }   
        intervs[from]=to;
    }
 
    int pos_b = 0, pos_e;
    for (auto i : intervs)
    {
        pos_e = i.first;
        if (pos_e>pos_b)
           os<<pos_b<<" "<<pos_e<<endl;
        pos_b = i.second;
    }
    if (pos_b < L)
        os<<pos_b<<" "<<L<<endl;
}
int main()
{
    stringstream ss;
    ss<<10<<endl<<3<<endl<<"5 6"<<endl<<"1 2"<<endl<<"4 9";
    scanSeq(ss, cout);
}
0
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,052
25.01.2021, 18:04 9
Цитата Сообщение от alexbmd Посмотреть сообщение
А) как еще можно ускорить данную логику ?
Бессмысленное занятие. Любой подход, пытающийся буквально моделировать "забор" и его "покраску", является тупиковым.

Однако если вы в какой-то другое задаче вам понадобилось заполнять диапазон в битовом массиве единицами, то естественный способ "ускорения цикла" очевиден: выполнять заполнение целыми словами (unsigned) -1 в тех частях диапазона, где "закрашено" целое слово.

Цитата Сообщение от alexbmd Посмотреть сообщение
Б)подскажите алгоритм (словесный код)
Классический off-line алгоритм вам уже подсказал Renji. Ваша задача - как раз off-line.

Для on-line задачи существуют структуры данных вроде interval tree, которые делают именно то, что вам нужно.
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
25.01.2021, 19:10 10
Цитата Сообщение от alexbmd Посмотреть сообщение
это всмысле если правый край больше ?
Это в смысле в отсортированном массиве отрезков А и Б следуют друг за другом. А пересекаются если левый конец Б попадает внутрь А.
0
2817 / 2325 / 703
Регистрация: 29.06.2020
Сообщений: 8,577
25.01.2021, 20:33 11
еще бы был правильный ответ на его пример, ...

Добавлено через 6 минут
оказалось проще чем я думал, сначала намудрил три тома

Добавлено через 28 минут
результат на приведенном файле, в 1 посте
8259 26667
1932691397 2000000000
с радостью приму критику

код:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <sstream>
#include <fstream>
#include <map>
 
using namespace std;
 
void scanSeq(istream & is, ostream & os)
{
    typedef  unsigned long long s_t;
    map<s_t , s_t> intervs;
    s_t L, N;
    is>>L;
    is>>N;
    pair<s_t, s_t> p;
    for (s_t i = 0; i<N; ++i)
    {
        is>>p.first>>p.second;
        intervs[p.first]=p.second;
    }
 
    s_t pos_b = 0, pos_e;
    for (auto & i : intervs)
    {
        pos_e = i.first;
        if (pos_e > pos_b)
           os<<pos_b<<" "<<pos_e<<endl;  // вывод "непокрашеного" "забора"
        if (i.second > pos_b) // игнорируем ВСЕ входящие и перекривающиеся диапазоны
            pos_b = i.second;  // сначало след, диапазона, если есть
    }
    if (pos_b < L) // хвост, если есть
        os<<pos_b<<" "<<L<<endl;
}
int main()
{
    // для файла
    ifstream ifs("input.txt");
    scanSeq(ifs, cout);
 
    // ручной тест
    // stringstream ss;
   // ss<<100<<endl<<5<<endl<<" 5 11 "<<" 4 9 "<<" 1 3 "<<" 40 70 "<<" 50 60 ";
   // scanSeq(ss, cout);
 
}
0
61 / 5 / 1
Регистрация: 03.06.2013
Сообщений: 354
Записей в блоге: 3
25.01.2021, 20:39  [ТС] 12
блин 502 ошибка похерила мой комент пишу вкратце-

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
выполнять заполнение целыми словами
ну на малых инпут массивах всё отлично а так да согласен, если не тупиковый то не разумно затратный как минимум.
НО как ни страно у меня проблемный не первый цикл (красящий) а второй (подсчитывающий) и это несмотря даже на ускорение ввиде перебора целыми int-ами, и ни как не могу понять почему он это делает так медленно :/

остальные алгоритмы посматрю спасибо

PS: Renji подсказал но я не понял как одним условием "Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки" покрыть все возможные варианты
0
2817 / 2325 / 703
Регистрация: 29.06.2020
Сообщений: 8,577
25.01.2021, 20:42 13
Цитата Сообщение от alexbmd Посмотреть сообщение
Renji подсказал но я не понял как одним условием "Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки" покрыть все возможные варианты
это только для отсортированных отрезков
мой код ("вроде") рабочий, только последний
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
25.01.2021, 20:43 14
Цитата Сообщение от alexbmd Посмотреть сообщение
PS: Renji подсказал но я не понял как одним условием "Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки" покрыть все возможные варианты
Пока Аmin<=Бmin<=Аmax, сливать А и Б в Amin,max(Аmax,Бmax). Ну и как выше напомнили, отрезки должны быть отсортированы по значению левого конца.
0
61 / 5 / 1
Регистрация: 03.06.2013
Сообщений: 354
Записей в блоге: 3
25.01.2021, 20:44  [ТС] 15
Цитата Сообщение от Renji Посмотреть сообщение
в отсортированном массиве отрезков А и Б следуют друг за другом.
они то следуют но левый край может равняться а может быть больше + правый может иметь три варианта... НО даже если этосделать (хотя я не доконца понял что вы имеете виду) то это первая часть задачи если я правильно понял - окрашивание. моё хоть и "в лоб" но затык всёже во второй части - подсчёт
0
1352 / 851 / 365
Регистрация: 26.02.2015
Сообщений: 3,799
25.01.2021, 20:44 16
Цитата Сообщение от alexbmd Посмотреть сообщение
Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки

Первый отрезок в массиве лежит такой (после сортировки отрезков): 1 4
Второй отрезок в массиве лежит такой (после сортировки отрезков): 3 79
Ты можешь сделать отрезок новый: 1 79 сразу и проверять со следующим отрезком.
0
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,052
25.01.2021, 20:48 17
Цитата Сообщение от alexbmd Посмотреть сообщение
но я не понял как одним условием "Пока отрезок А пересекает идущий за ним отрезок Б, объединяй отрезки" покрыть все возможные варианты
Существенно более простая реализация получится, если хранить в отсортированном списке не отрезки, а индивидуальные концы отрезков, с одной координатой и пометкой левый-правый.

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

Возможно это будет чуть менее эффективно по памяти...
0
1352 / 851 / 365
Регистрация: 26.02.2015
Сообщений: 3,799
25.01.2021, 20:49 18
А ты пробовал операции вывода на консоль убрать из цикла, кстати?

Добавлено через 1 минуту
А все, вижу, что тебе их вывести надо.
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
25.01.2021, 21:00 19
Цитата Сообщение от alexbmd Посмотреть сообщение
они то следуют но левый край может равняться а может быть больше + правый может иметь три варианта... НО даже если этосделать (хотя я не доконца понял что вы имеете виду) то это первая часть задачи если я правильно понял - окрашивание. моё хоть и "в лоб" но затык всёже во второй части - подсчёт
Да Господи...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Line
{
public:
    bool operator<(const Line&line)const{return x<line.x;}
 
    int x,y;
};
 
int main()
{
    std::size_t lenght,lineListSize;
    std::cin>>lenght>>lineListSize;
    std::vector<Line> lineList;
    for(std::size_t i=0;i<lineListSize;++i)
    {
        int x,y;
        std::cin>>x>>y;
        lineList.push_back({x,y});
    }
    std::sort(lineList.begin(),lineList.end());
    auto writePos=lineList.begin();
    for(auto readPos=lineList.begin()+1;readPos<lineList.end();++readPos)
    {
        if(writePos->x<=readPos->x && readPos->x<=writePos->y)
            writePos->y=std::max(writePos->y,readPos->y);
        else
            *++writePos=*readPos;
    }
    lineList.erase(++writePos,lineList.end());
    std::cout<<"{0,"<<lineList.front().x<<"} ";
    for(auto line=lineList.begin();line+1<lineList.end();++line)
        std::cout<<"{"<<line[0].y<<" "<<line[1].x<<"} ";
    std::cout<<"{"<<lineList.back().y<<","<<lenght<<"}";
    return 0;
}
1
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,052
25.01.2021, 21:07 20
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Существенно более простая реализация получится, если хранить в отсортированном списке не отрезки, а индивидуальные концы отрезков, с одной координатой и пометкой левый-правый.
Реализация через точки (особо не тестировал)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <vector>
#include <algorithm>
#include <iostream>
 
int main()
{
  int length = 0;
  std::cin >> length;
 
  unsigned n_segments = 0;
  std::cin >> n_segments;
 
  std::vector<std::pair<int, int>> points; 
 
  for (unsigned i = 0; i < n_segments; ++i)
  {
    int xl = 0, xr = 0;
    std::cin >> xl >> xr;
    points.emplace_back(xl, +1);
    points.emplace_back(xr, -1);
  }
 
  points.emplace_back(length, +1);
 
  std::sort(points.begin(), points.end());
 
  int n_coverage = 0;
  int prev_x = 0;
 
  for (const auto &point : points)
  {
    if (n_coverage == 0 && prev_x != point.first)
      std::cout << prev_x << " " << point.first << std::endl;
 
    prev_x = point.first;
    n_coverage += point.second;
  }
}
Добавлено через 2 минуты
Цитата Сообщение от Renji Посмотреть сообщение
Да Господи...
На большом тесте выдает {0,0} как некрашеный. Неаккуратненько..
0
25.01.2021, 21:07
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.01.2021, 21:07
Помогаю со студенческими работами здесь

Ускорить работу вложенного цикла for() C#
Добрый день. Имеется цикл в котором подбираются коэффициенты к массивам таким образом, чтобы коэф...

Welcome to experts C++!
Написать программу, считывающую две строки (с нуль-окончанием) длиной до 80 символов и выводящую...

Minsk.BelHard.vacancies: Java Experts, Team Lead, PM
Гарантируем высокое вознаграждение (от 1000-2500 по результатам собеседования) и все условия для...

Как из цикла вывести данные для другого цикла?
Вообщем такая фигня... Как из цикла вывести данные для другого цикла? а то он не видит Пример...

Program1.pas(7): Параметр цикла for в PascalABC.NET должен описываться в заголовке цикла. Как исправить?
Program1.pas(7) : Параметр цикла for в PascalABC.NET должен описываться в заголовке цикла. Как...

Как проверить логику и ОУ ?
Задался таким вопросом. Как прозвонить логику и ОУ ? Есть логический пробник в мультиметре для...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru