Ответы пользователя по тегу Программирование
  • Задача про стену и кирпичи. Как решить?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Строите матрицу перехода между рядами (43х43, как описано в ответе Andy_U ), потом возводите её в 9-ю степень (поскольку у нас 9 переходов) и считаете сумму всех элементов (поскольку первый и последний ряд могут быть любыми). Всё.
    Работает для любого числа рядов, хоть для триллиона :) Только потребуется быстрое возведение в степень.
    Но это будет число способов построить стену. Если имелось в виду число наборов кирпичей (сколько может быть кирпичей 3x1 и сколько 4x1), то надо подумать, как сделать проще всего.
    Ответ написан
  • Как улучшить скорость функции?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Записать условие в виде (a+1)*(b+1) == n*(n+1)/2+1 = N, и для чисел a от (n+1)/2 до n проверить, делится ли N на a+1. Если делится, то b=N/(a+1)-1. На всякий случай, проверить, что b < n+1.
    При желании, перебор можно сократить примерно в 12 раз. Но тогда вместо проверки делимости надо будет быстро проверять, является ли число полным квадратом - что может быть не очень просто.
    Ответ написан
    2 комментария
  • Как наличие одинаковых элементов в сортируемой последовательности влияет на быструю сортировку?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Смотря как писать сортировку - здесь всё зависит от мелких деталей.
    Если не помнить, что элементы могут быть одинаковыми, легко свалиться в O(n^2).
    Можно написать так, что число сравнений не изменится, но одинаковые элементы будут вхолостую переставляться друг с другом.
    Можно на каждом шагу бояться, что могут встретиться одинаковые элементы, и делить массив на три части - меньше опорного, равные ему и большие его. Тогда при большом количестве одинаковых элементов будет работать быстро, но когда одинаковых элементов нет - то число сравнений будет в 1.6 раза больше.
    Можно при разделении смотреть, был ли хоть один элемент равен опорному, и отделять равные только если был. Тогда будет плохо, когда каждый элемент встречается ровно два раза.
    Есть и другие способы. И всё это будет quicksort. Если всё написать правильно, то чем больше одинаковых элементов, тем быстрее будет сортировка.
    Ответ написан
    1 комментарий
  • Как назвать класа элемента библиотеки (той где книги и журналы)?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Paper, Publication
    Ответ написан
    Комментировать
  • Как найти 3 кратчайших пути в графе?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    В каждой вершине хранить не более трёх кратчайших путей до неё. В Дейкстре использовать очередь без модификации веса. Если очередной путь, взятый из очереди, лучше третьего по порядку пути, сохранённого в вершине, (или сохранено не более двух путей) - добавляем этот путь в вершину, а все его продолжения - в очередь.
    Проблема в том, что в путях могут появиться циклы. Например, для графа из двух вершин с тремя рёбрами
    (1,2, w=1)
    (1,2, w=3)
    (1,2, w=5)
    будут выданы пути 1-2 (по первому ребру), 1-2 (по второму ребру) и 1-2-1-2 (по первому ребру). Если циклы нежелательны - придётся возиться дольше
    Ответ написан
    Комментировать
  • Как сгенерировать окружности на сфере, что бы они оптимально перекрывали друг-друга?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Это известная проблема. Пока её решили до 10 кругов и ещё для некоторых чётных значений. Впрочем, всё это сведения 25-летней давности, свежих результатов найти не удаётся. Вот статья, где разбирается построение для 11 кругов (правда, я её не читал, и не знаю, есть ли там окончательное решение для этого случая):
    https://eudml.org/doc/141375
    Или у вас задача - "дан радиус сферы и радиус круга, найти минимальное число кругов"? Или можно задать примерный радиус (или примерное число кругов) и найти какое-нибудь решение, близкое к оптимальному, для этого случая?
    В общем, сейчас задача упирается в вопрос "а зачем?". Если нужно точное решение для написания докторской диссертации - то решайте. Если есть какая-нибудь практическая цель - напишите, какая, и будем искать реалистичные приближения.

    UPD. В общем, берёте икосаэдр, и каждую грань делите на маленькие правильные треугольники. Вершины этих треугольников и дадут центры кругов. Радиус придётся считать исходя из картинки вблизи вершины икосаэдра - там треугольники заметно искажаются. Возможно, радиальное расстояние между точками там придётся слегка уменьшить.
    Ответ написан
    7 комментариев
  • Как "вставить" биты в число?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Если нужно сделать так, как в вашем примере (т.е. вставить биты 2048,1024,256,16), то так:
    y=((x&0xf00)<<4)+((x&0x80)<<2)+((x&0x70)<<1)+(x&0xf);

    Но так биты никто не нумерует. Обычно они нумеруются, начиная с младшего - иногда он считается за нулевой, иногда за первый.
    Ответ написан
    Комментировать
  • Перебор массива циклом или сверка значений проверкой?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    На С++ прямая проверка работает примерно вдвое быстрее, чем проверка циклом. Я проверял для массива из 10 элементов (проверял, входит ли число в первые 10 простых чисел). С циклом проблема ещё и в том, что для такого "if" трудно написать else-часть - нужно либо добавлять лишнюю логическую переменную, либо использовать goto.
    Ответ написан
    Комментировать
  • Можно ли одной bitwise операцией (без циклического сдвига) определить степень двойки(номер бита)?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Можно взять остаток от деления на 37, и дальше по табличке. Но это может оказаться дороже, чем цикл.
    Или за 5 операций AND:

    int n=0;
    if(x&0xffff0000) n+=16;
    if(x&0xff00ff00) n+=8;
    if(x&0xf0f0f0f0) n+=4;
    if(x&0xcccccccc) n+=2;
    if(x&0xaaaaaaaa) n++;

    Хотя через CLZ лучше.
    Ответ написан
    Комментировать
  • PHP: как сгруппировать близкие по значению элементы массива?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Непонятная задача.
    Во-первых, решений может быть много. Например, пусть границы - abs(dx) <= 5, abs(dy) <= 5. Точки A=(0,0), B=(4,4), C=(7,7). Тогда решением будет и {A,B},{C} и {A},{B,C}. Из них правильно какое-то одно, или оба?
    А если точки A=(0,0), B=(4,4), C=(7,7), D=(11,11)? Годится ли решение {A},{B,C},{D}? В нём больше групп, чем в {A,B},{C,D}, но центральная группа плотнее.
    И наконец, является ли условие "posX && posY в группе отличаются каждая друг от друга не более чем на +\- какое-то значение" единственным? Если да - достаточно создать N групп, по одному элементу в каждой. Условие будет выполнено. А если нет - попытайтесь объяснить, почему конкретно это решение не годится. Сформулировать условие, которое нарушено. Может быть, тогда станет понятнее, что же это за задача. А пока это лишь пожелание "сделайте мне красиво".

    А если задача не формализована - ищите слово "кластеризация". Про неё много интересного написано.
    Ответ написан
    2 комментария
  • Как написать "Hello World" на машинном коде?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    На SO есть пример, как это сделать на ассемблере с использованием kernel32.lib:
    stackoverflow.com/questions/1023593/how-to-write-h...
    Можно попробовать начать оттуда, потом научиться переводить это в машинный код (например, посмотрев в листинг ассемблера).
    Ответ написан
    Комментировать
  • Для чего программисту нужно знать физику?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Этот же вопрос я задал себе неделю назад. После того, как исписал пару страниц физическими расчётами: нужно было определить направление оси вращения по показателям инклинометров, при неравномерном вращении прибора - т.е. с учётом центростремительного и тангенциального ускорений. Приступом не взялось, точность получилась порядка 0.01 градуса, а надо на порядок лучше... Надо дорабатывать модель. Так что, иногда физика требуется. И даже не обязательно в играх.
    Ответ написан
    Комментировать
  • Как найти кратчайший путь в лабиринте?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Заведите ещё один массив и кладите в него направление, откуда пришли в данную клетку. Проще всего это направление передать параметром в FindPath. Потом пройдите по этим направлениям от финиша до старта.
    Другой вариант - на обратном проходе искать соседнюю клетку со значением tempMap на 1 меньшим, чем в данной клетке, и идти в неё. Это дольше писать и оно чуть медленнее работает, но требует меньше памяти.
    Лабиринт действительно на сетке из шестиугольников?
    Ответ написан
  • Как сформировать рёбра на основе списка вершин объекта?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Сначала найдите выпуклую оболочку. Она даст и рёбра, и грани. Провести плоскость через три точки одной грани - дело техники, а вот если граней нет, то задача вообще некорректна. По одному и тому же набору вершин можно построить много разных тел.
    Ответ написан
    1 комментарий
  • Как выбрать какую функцию вызвать на этапе выполнения программы?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Например, так:
    double FindMinimum(Func<double,double,double>F,out double x1,out double x2){
         x1=x2=0;
         return F(x1,x2);
    }

    Тогда вызов поиска минимума будет double zmin=FindMinimum(f1,out x,out y);
    Ответ написан
    Комментировать
  • Как решать задачу на счастливые билеты?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Как-то так:

    int S0[37],S1[37],S2[37],S3[37],S4[37];
    
    void Expand(int *a,int *b,int n){
    	int s0=0;
    	for(int i=0;i<n+10;i++){
    		if(i<n) s0+=a[i];
    		if(i>=10) s0-=a[i-10];
    		b[i]=s0;
    	}
    }
    
    int Conv(int *S,int balance,int m){
    	int res=0;
    	while(--m>=0) res+=S[m]*S4[balance+m];
    	return res;
    }
    
    // number of tickets in 0..u-1
    int NHappy(int u){
    	int res=0;
    	int balance=0;
    	int digit;
    
    	digit=u/10000000; u%=10000000;
    	for(int i=0;i<digit;i++) res+=Conv(S3,balance++,28);
    	digit=u/1000000; u%=1000000;
    	for(int i=0;i<digit;i++) res+=Conv(S2,balance++,19);
    	digit=u/100000; u%=100000;
    	for(int i=0;i<digit;i++) res+=Conv(S1,balance++,10);
    	digit=u/10000; u%=10000;
    	for(int i=0;i<digit;i++) res+=S4[balance++];
    	digit=u/1000; u%=1000;
    	for(int i=0;i<digit && balance>=0;i++) res+=S3[balance--];
    	digit=u/100; u%=100;
    	for(int i=0;i<digit && balance>=0;i++) res+=S2[balance--];
    	digit=u/10; u%=10;
    	for(int i=0;i<digit && balance>=0;i++) res+=S1[balance--];
    	if(balance>=0 && balance<u) res++;
    	return res;
    }
    
    void __cdecl main(){
    	S0[0]=1;
    	Expand(S0,S1,10);
    	Expand(S1,S2,19);
    	Expand(S2,S3,28);
    	Expand(S3,S4,37);
    
    	int m,n;
    	for(;;){
    		printf("m,n: ");
    		scanf("%d%d",&m,&n);
    		printf("Result: %d\n",NHappy(99999999)+1-NHappy(m)-NHappy(99999999-n));
    	}
    }

    Проверок входных данных не делается. На простых тестах результаты были правильными. Работает, по моим оценкам, быстрее, чем за 2000 операций. Если нужно проверять много диапазонов, то можно предварительно вычислить частичные суммы Conv() в циклах, и тогда любой диапазон сосчитается за два десятка операций (и при этом не будет требовать гигабайта памяти).

    UPD: Вот оптимизированный вариант:
    int S[8][38];
    
    void InitS(){
    	for(int i=1;i<38;i++) S[0][i]=1;
    	for(int a=1;a<9;a++){
    		int s0=0;
    		for(int i=1;i<=37;i++){
    			s0+=S[a-1][i];
    			if(i>10) s0-=S[a-1][i-10];
    			S[a][i]=s0;
    		}
    	}
    }
    
    // number of tickets in 0..u-1
    int NHappy(int u){
    	int res=0;
    	int balance=36;
    	for(int a=7,b=10000000;a>=0;a--,b/=10){
    		int digit=u/b;
    		u%=b;
    		int b1;
    		if(a>3){
    			balance-=9;
    			res+=S[a][b1=balance+digit]-S[a][balance];
    		} else{
    			b1=balance-digit; if(b1<0) b1=-1;
    			res+=S[a][balance+1]-S[a][b1+1];
    		}
    		balance=b1;
    	}
    	return res;
    }
    
    void __cdecl main(){
    	InitS();
    	int m,n;
    	for(;;){
    		printf("m,n: ");
    		scanf("%d%d",&m,&n);
    		printf("Result: %d\n",NHappy(99999999)+1-NHappy(m)-NHappy(99999999-n));
    	}
    }

    Не спрашивайте, почему :)
    Ответ написан
    3 комментария
  • Является ли наличие двух одинаковых констант в коде признаком не оптимальности решения?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Зависит от длины константы. Что короче - загрузить её в регистр непосредственно в команде, или взять из памяти (указав в команде адрес)? Сильно зависит от процессора.
    В целом, одинаковые константы в алгоритме это не страшно. Хуже, когда одно и то же условие приходится проверять много раз. Или, что ещё страшнее, условия, следующие одно из другого (проверили, что a < b, а потом проверяем, что a+c < b+c). Такое часто встречается в геометрии. И в этом случае над алгоритмом стоит поработать.
    Ответ написан
    Комментировать
  • Как обстоят дела с программным обеспечением на огромных объектах?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    На авианосце, наверняка, огромное количество блоков управления, датчиков, микроконтроллеров и микропроцессоров, а так же более крупных управляющих узлов. И для каждого из них нужна своя программа. А может быть, и специально настроенная операционная система. Все ли датчики и блоки управления дублируются - вероятно, зависит от их важности. Иногда дешевле и надёжнее продублировать, иногда поставить периодическое тестирование, иногда предусмотреть работу при отказавшем узле. Предусмотрено ли несколько версий программ управления на случай "если в одной версии оказалась ошибка - поставим другую" - не уверен. Разве что на время очередного апгрейда и тестирования в реальных условиях.
    Но это всё догадки.
    Ответ написан
    Комментировать
  • Какие ресурсы "экономить" при алгоритмизации?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Если вы хотите экономить память, то проблема будет не в переменных, а в больших структурах (списки, массивы, словари...). Мне чаще всего встречаются такие ситуации:
    - память в обмен на время. Запоминать результаты или вычислять заново? Иногда здесь удаётся обменять экспоненциальное время на полиномиальное, или уменьшить степень полинома на 1 или на 2. Но чаще выигрыш идёт только в константу раз (хотя в узком месте это может быть немаловажно). Впрочем, иногда вычислить функцию оказывается быстрее, чем найти её значение в таблице - так что надо такие оптимизации проверять.
    - замена обработки большого массива в памяти на послойную обработку (когда очередной фрагмент/строка/двумерный слой трёхмерного массива... вычисляется, обрабатывается, а уже ненужный слой забывается). Здесь память экономится за счёт серьёзного усложнения кода - приходится писать всякие конвейеры. Зато появляется шанс сэкономить ещё и время с помощью параллельной обработки.
    - хранение данных, которые должны быть в памяти, в упакованном виде. Трудно читать, очень трудно писать, код усложняется, время теряется. Но появляется шанс уложиться в 3 ГБ и остаться в 32-битном режиме (если это важно).
    - хранение в памяти против чтения из файла. Либо будет теряться время, либо усложняться код (если сумеете воспользоваться асинхронным чтением/записью).
    - в тяжелых случаях - экономия байтов кода (это если пишете на ассемблере). Может пригодиться, если действительно пишете сервер для кофеварки. Но возможно, здесь лучше попытаться поставить процессор помощнее.

    Сначала пишите, как проще, но если есть риск развития проекта за пределы текущих ресурсов, предусмотрите возможность постепенного перехода на более экономные по памяти (или, там где надо - по времени) алгоритмы.
    Ответ написан
    2 комментария
  • Как правильно закодить раскраску графа в с++?

    Mrrl
    @Mrrl
    Заводчик кардиганов
    Рекурсией. Находите нераскрашенную вершину, у которой меньше всего вариантов раскраски, и красите её во все возможные цвета. После каждой покраски - рекурсивно вызываете эту же функцию. Если оказалось, что неиспользованных цветов столько же, сколько нераскрашенных вершин - красите каждую в отдельный цвет и возвращаете как решение.
    Ответ написан
    Комментировать