Как сократить время работы программы

Решил написать простую программу в целях обучения и практики. Решение правильное, но очень медленное. Сдаю задачку на сайте, 13 из 27 тестов выдаёт около 2 секунд, а нужно меньше 1 секунды. Постарался максимально сократить все if-ы, которые только возможно было, но и это не помогает. Думаю, что основное время затрачивается на прокрутку цикла, но иначе задачу не решить же.

У других пользователей среднее время в этой задачке от 14 до 100 мс. Я просто недавно начал, и может этот алгоритм который я написал совсем никак не ускорить, но по другому я просто не представляю как можно это решить. условие задачи Новый русский Витек приватизировал участок в Междолине размером m квадратов с севера на юг и n квадратов с запада на восток.

Он решил построить в пределах этого участка дом размером a квадратов с севера на юг и b – с запада на восток. Некоторые квадраты радиоактивны, и Витек не хочет на них строить дом. Кроме того, Витек хочет, чтобы расстояния от стен до границ участка выражалась целым числом квадратов. Долго выбирал он место для дома, но так и не выбрал – слишком много вариантов. А сколько?

Как увеличить время работы iPhone

Начал наш герой считать, но не сумел – плохо математику учил. Помогите ему. Входные данные Напишите программу, которая считывает числа m, n, a, b, k (1 ≤ a ≤ m ≤ 5000, 1 ≤ b ≤ n ≤ 5000, 0 ≤ k ≤ m * n), где m, n – размеры участка, a и b – размеры дома, k – количество радиоактивных квадратов, а затем k неповторяющихся пар чисел i и j (1 ≤ i ≤ m, 1 ≤ j ≤ n), которые определяют координаты радиоактивных квадратов. Выходные данные Вывести искомое количество способов расположения дома. На С++

#include using namespace std; int main() < int m, n, a, b, k, S, Ox, Oy, Oxmain = 1, Oymain = 1, l, t; // m висота n ширина; a висота b ширина bool y = false; cin >> m >> n >> a >> b >> k; int i[100000]; for (l = 1; l > i[l] >> i[l + 1]; > S = a * b; l = 0; while (Oymain > > Oy = Oymain; > if (y); else l++; y = false; Oxmain++; > Oxmain = 1; Oymain++; > cout

Отслеживать

задан 9 окт 2020 в 19:39

user410415 user410415

У вас матрешка из 5-ти вложенных циклов, хотя вложенность 2-й степени циклов уже дает O(n^2) .

9 окт 2020 в 19:55

Матрица m * n заполнена нулями, к точкам с данными индексами, присваиваются единицы. Теперь нужно считать количество площадей, размером a * b, где не встречаются элементы с ненулевым значением

Источник: ru.stackoverflow.com

Отключение ВСЕХ ненужных служб в Windows 10 | Оптимизация Windows 10

Читайте также:
Как пригласить игрока в реферальную программу World of Tanks

Как сократить время работы программы

: 167

Как сократить время работы программы

Даётся число n. Нужно вывести количество пар чисел, сумма которых будет равна числу n, и сумма цифр которых будет равняться сумме цифр числа n.
Например, число 11.
Пары, которые подходят:
11 0
0 11
1 10
10 1.
Значит, ответ 4, т.к. 4 пары.
Я делал так:
делаю цикл от 1 до n, и перебираю варианты: 0 и n, 1 и n-1, 2 и n-2, и т.д.
Записываю числа в строковую, потом каждый символ превращаю в цифру и помещаю в массив. В массиве подсчитываю сумму элементов.
Проверяю, sum=sum1+sum2 или нет.
И считаю кол-во вариантов.
Но число может быть от 1 до 10^100.
И при больших числах слишком долго выполняется цикл, а потом и в longint не влезает.
Подскажите, как еще можно реализовать это задание?

var a,a1,a2:array[1..100]of byte; 3 массива, первый для n, второй и третий нужны при перебирании чисел fi,fo:text; i,n,n1,n2,k,sum,i1,i2,l,sum1,sum2:longint; x,y,z:longint; s,s1,s2:string; begin Assign(fi,’sequence.in’); Assign(fo,’sequence.out’); Reset(fi); Rewrite(fo); Read(fi,x);=читает число n (у меня x) Str(x,s);преобразуем его в строку n:=length(s); l:=0; for i:=1 to 100 do a[i]:=0; элементы первого массива обнуляем, на всякий случай for i:=1 to n do val(copy(s,i,1),a[i],k); число x по цифрам кидаем в массив for i:=1 to n do sum:=sum+a[i];считаем сумму цифр числа x y:=0; z:=x; for i:=1 to x do begin вот этот цикл слишком долго идет при больших числах for i1:=1 to 100 do a1[i1]:=0; for i2:=1 to 100 do a2[i2]:=0;обнуляем массив 2 и 3, т.к. при новом проходе через цикл они буду заполнены Inc(y); Dec(z); sum1:=0; sum2:=0; Str(y,s1); n1:=length(s1); Str(z,s2); n2:=length(s2); for i1:=1 to n1 do val(copy(s1,i1,1),a1[i1],k); for i2:=1 to n2 do val(copy(s2,i2,1),a2[i2],k); for i1:=1 to n1 do sum1:=sum1+a1[i1]; for i2:=1 to n2 do sum2:=sum2+a2[i2]; считаем сумму цифр первого и второго числа для проверки if (sum1+sum2=sum)then begin проверяем, подходит ли условие Inc(l);наращиваем счетчик end; if (sum1+sum2=sum)and(y=z) это на случай, к примеру, для 20. То есть бывает 0 20 и 20 0, две пары. А с 10 10 и 10 10 аналогично, просто не видно, что их меняют местами then Inc(l); end; Inc(l); Программа посчитает x 0, а 0 x не посчитает. Write(fo,l); Close(fo); end.

Последний раз редактировалось dimon_snake; 30.01.2016 в 22:05 .

Источник: www.programmersforum.ru

Оптимизация времени выполнения программы на С++ (убираем условные переходы)

image

При оптимизации времени выполнения алгоритма, использующего LDPC декодер, профайлер привел к функции, вычисляющей следующее значение:

где a и b — целые числа. Количество вызовов шло на миллионы, а реализация ее была достаточно проста и бесхитростна:

int LLR(int a, int b) < if (a>0) return (b>0) ? __min(a,b) : -__min(a,-b); else return (b>0) ? -__min(-a,b) : __min(-a,-b); >

Читайте также:
Задачи программы развитие венгера

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

тестовый проект

#include static inline int LLR(int a, int b) < if (a>0) return (b>0) ? __min(a,b) : -__min(a,-b); else return (b>0) ? -__min(-a,b) : __min(-a,-b); > int _tmain(int argc, _TCHAR* argv[]) < SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL); srand(0); int x(0); __int64 t1,t2; QueryPerformanceCounter((LARGE_INTEGER*) for (size_t i=0;i>4;i++) < int a = rand() — RAND_MAX / 2; int b = rand() — RAND_MAX / 2; /* x += LLR(a,b);*/ >QueryPerformanceCounter((LARGE_INTEGER*) t2 -= t1; QueryPerformanceFrequency((LARGE_INTEGER*) _tprintf_s(_T(«%f»),t2/(t1*1.)); return 0; >

Сборка производилась в MSVS 2008 в конфигурации Release (настройки по умолчанию) для платформы x86.

Для начала, закомментируем вызов расчетной функции чтобы оценить время выполнения цикла с генерацией случайных чисел (к сожалению, вызов QueryPerformanceCounter() сам по себе довольно медленный и приводит к значительному искажению результата если его делать внутри цикла). Запускаем проект несколько раз, чтобы убедится в повторяемости результата. На машине с процессором Intel Core i7-3770 c частотой 3.4 ГГц время выполнения составляет в среднем 9.2 секунды. Если раскомментировать вызов расчетной функции, пересобрать проект и повторить эксперимент — получаем примерно 11.5 секунд. Прирост времени выполнения налицо, с ним и будем бороться.

Попробуем избавиться от условных операторов. Для начала выясним знак произведения a и b. Вычислять его в лоб некорректно из-за возможного переполнения. Так как нам важен только знак (то есть значение бита знакового разряда целого числа), то уместно воспользоваться операцией xor для определения знака произведения a и b. Далее, сдвинем результат a xor b вправо на 31 бит (оставляя только знаковый разряд) и получим 0 в случае неотрицательного числа и 1 в случае отрицательного. Умножим это значение на два, вычтем из единицы и получим -1 для отрицательного числа и 1 для неотрицательного:

int sign = 1-2*((unsigned)a^b)>>31);

Теперь рассчитаем модули a и b. Аналогичным методом определяем знаковые коэффициенты a и b и умножаем на них:

int c; c = 1-2*(((unsigned)a)>>31); a *= c; c = 1-2*(((unsigned)b)>>31); b *= c;

Перейдем к расчету минимума. Поскольку a и b уже имеют неотрицательные значения, рассчитать минимум можно, ориентируясь на знак их разности:

int numbers[2], min; numbers[0] = b; numbers[1] = a; a -= b; c = (unsigned(a))>>31; min = numbers[c];
Соберем все вместе и получим
следующую функцию
static inline int LLR_2(int a, int b) < int sign, numbers[2]; sign = 1-2*(((unsigned)a^b)>>31); a *= 1-2*(((unsigned)a)>>31); b *= 1-2*(((unsigned)b)>>31); numbers[0] = b; numbers[1] = a; a -= b; return sign*numbers[((unsigned)a)>>31]; >

Читайте также:
Как посмотреть какие программы были установлены

Заменим вызов LLR() на LLR_2() и посмотрим, что получилось.

В ассемблерном коде теперь ни одного условного перехода, зато появились три инструкции целочисленного умножения imul (умножение на 2 компилятор сам заменяет на сдвиг). Прогнав тестовую программу, получаем следующий результат — время выполнения составляет 9.4 секунды! Итого, сравнивая времена «нетто» (2.1 и 0.2 секунды соответственно) для двух вариантов расчета искомого значения, получаем десятикратное * увеличение скорости выполнения требуемой операции.

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

unsigned int mask[] = ; unsigned int constant[] = ; int c = ((unsigned)a)>>31; a = a^mask[c]+constant[c];

И наконец, заменим сдвиг вправо на 31 бит единичным циклическим сдвигом влево с помощью функции _rotl(). Забегая вперед отметим, что компилятор преобразует ее вызов напрямую в инструкцию rol без использования call. Соберем все вместе еще раз и получим

третий вариант

static unsigned int mask[] = ; static unsigned int constant[] = ; static inline int LLR_3(int a, int b)

Заменяем вызов LLR()_2 на LLR_3() и видим, что значимого прироста это не дает (время выполнения составляет примерно те же 9.4 секунды с небольшой разницей в третьем знаке в меньшую сторону). Получается, что imul на современных процессорах выполняется довольно быстро!

Вернемся к алгоритму, с которого все началось. Описанной оптимизацией только лишь одной функции удалось сократить время обработки единичного блока данных со 160 до 140 секунд (при выполнении на i7), что составляет более 10% и является весьма неплохим результатом. На очереди еще несколько похожих функций…

Ну и напоследок предлагаю вариант реализации функции определения максимума двух целых 32-разряздных чисел. Написан он был уже чисто из академического любопытства. Желающие могут не спешить заглядывать под спойлер и попробовать реализовать подобное сами. Вариант без условных переходов работает примерно втрое быстрей стандартного макроса __max() (при выполнении на i7). Удачи в оптимизации ваших программ!

Скрытый текст

static inline int max(int a, int b) < int numbers[2][2]; numbers[0][0] = b; numbers[0][1] = a; numbers[1][0] = a; numbers[1][1] = b; int sign_a = (unsigned)a>>31; int sign_b = (unsigned)b>>31; int sign_ab = (unsigned)(a^b)>>31; int abs_a = (1-2*sign_a)*a; int abs_b = (1-2*sign_b)*b; int sign_a_b = (unsigned)(abs_a-abs_b)>>31; int c0 = sign_ab; int c1 = ((1^(sign_a_b)^(sign_a | sign_b)) sign_a); int result = numbers[c0][c1]; return result; >

*UPD. В комментариях пользователь shodan привел пример, в котором rand() убран из подсчета времени, а чтение данных производится из заранее сформированного массива. В этом случае прирост производительности приблизительно трехкратный. По-видимому, это связано с более эффективной работой конвеера при чтении данных из массива.

  • программирование
  • с++
  • алгоритмы
  • оптимизация программ

Источник: habr.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru