Top.Mail.Ru
? ?
О переводе стрелок
Imagealgrid
В котором часу осуществляется переход с зимнего времени на летнее? Вопрос не совсем праздный.

Не так давно пришлось столкнутся с некоторыми проблемами из-за того, что приборы учета газа и тепла, произведенные в России, были по умолчанию настроены так, что переход этот осуществлялся в 2 часа ночи (наступало сразу 3:00). Это верно для России. В Молдавии же, как оказалось, этот переход осуществляется в 3 часа ночи (наступает 4). По крайней мере, так считают Linux, Windows и прочие. Это действительно похоже на правду, так как для всех стран ЕС определено единое время перевода стрелок: 01:00 GMT, что соответствует 03:00 по Кишиневскому зимнему времени. Молдавия, конечно, не страна ЕС, но с нашим стремлением во всем внедрять пресловутые "евростандарты", ничего удивительного здесь нет.

P.S.
Хочется верить, что в России одумаются и возобновят практику перехода на летнее/зимнее время. А то ведь при таких делах разговоры об энергоэффективности и запрет 100-Ваттных ламп накаливания совсем уж нелепо смотрится. Ну да это уже совсем другая история...

Перезапуск текущего процесса в Linux
Imagealgrid
Как перезапустить программу? Очевидно, вызвав exec(...) Но для этого нужно знать имя исполняемого файла программы. Если задать это имя жестко в программе, то это ограничит возможности переименования/перемещения программы. В Linux можно вызвать что-то вроде:

 execlp("/proc/self/exe", "a.out", NULL);

/proc/self/exe  (или  /proc/<pid>/exe ) - это ссылка, всегда указывающая на исполняемый файл программы.
Для Solaris нужно использовать /proc/pid/object/a.out


Иголка в стоге сена
Imagealgrid
Все-таки выбрать хорошее имя для переменной - большое дело! Вот, например, как названы параметры функции strstr():

char *strstr(const char *haystack, const char *needle);

Забавно :)
Отлично запоминается, и сразу все понятно.
Метки:

О разрушителях мифов, резонансе и мостах
Imagealgrid

Была у разрушителей мифов такая передача, в которой они пытались разрушить мост, воздействуя на него с резонансной частотой. В другом сюжете они пытались воспроизвести некое устройство (по патенту Теслы), которое, войдя в резонанс со зданием, якобы могло его разрушить. Что интересно, ни в одном из этих сюжетов, разрушители не измеряли частоту собственных колебаний исходной конструкции. Да и конструкции были довольно своеобразными в этом плане - например, имитация деревянного моста, у которой противоположные концы не были жестко закреплены или небольшая модель здания, от которой потом переходили к полноразмерным испытаниям (рассчитывая работать на той же частоте?).

Но я это все не к тому, чтобы раскритиковать авторов - передача забавная, посмотреть интересно, если оставить за скобками всякие заумные научности :) Вся эта история с резонансом навела меня на другую мысль - возможно у сложной конструкции в процессе "раскачивания" резонансная частота будет меняться. (А может быть таких пиковых частот будет несколько с различной добротностью колебательной системы на этих частотах? Хотя я не уверен, что на самом деле бывает несколько подобных частот, за исключением кратных основной, резонансной.)

Почему бы тогда не встроить в пресловутое устройство Теслы акселерометр, который будет периодически измерять частоту собственных колебаний системы и соответствующим образом корректировать частоту устройства, воздействующего на систему? Может быть тогда и получится разрушить мост или здание? :)

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


ACM problems/solutions (SouthEastern European Regional Contest, problem G)
Imagealgrid
Задачи 2009-го года.
http://acm.ro/2009/index.html
http://acm.ro/2009/prob/ACMproblems2009.zip
(копия  http://acm.voroh.com/acm_ro_2009/ACMproblems2009.zip)

Задача G
http://acm.ro/2009/prob/probleme/G.pdf
(копия http://acm.voroh.com/acm_ro_2009/G.pdf )
решение: http://acm.voroh.com/acm_ro_2009/G2009.CPP


Эту задачу я решил, применив методы динамического программирования. Ниже следует описание использовавшейся формулы. Кроме того, в исходном паттерне все последовательности из 2-х и более звездочек были заменены на одну звездочку – это несколько ускорило работу программы.


Обозначим:

P[x..y] – паттерн, состоящий из символов с x по y исходного паттерна
SP[x..y] – строка, состоящая из символов с x по y исходной строки super password
A[i, j] – минимальная сложность пароля, соответствующего паттерну P[1..i] в строке SP[1..j] (или -1, если такого не существует)
W[k] – сложность символа SP[k]
Считаем, что символы в P и SP нумеруются, начиная с единицы.


Для начала, положим A[0,j] = 0 для всех j
Далее A[i,j] будет определяться следующим образом

1. Если P[i] = ‘?’, то
Если A[i-1, j-1] = -1 или j =0, то A[i,j] = -1,
иначе A[i,j] = A[i-1, j-1]+W[j]

2. Если P[i] – буква
Если A[i-1, j-1] = -1 или P[i]=SP[j] или j =0, то A[i,j] = -1,
иначе A[i,j] = A[i-1, j-1] +W[j]

3. Если P[i] = ‘*’
A[i,j] = A[i-1,k]+W[k+1]+…+w[j],
где k – наибольшее значение, для которого k<=j, A[i-1,k] != -1
Если таких k не существует, то A[i,j] = -1


Поясню последний пункт, а именно, почему выбирается именно наибольшее значение k. Пусть существует меньшее значение k1<k, для которого


A[i-1,k1]+W[k1+1]+…+W[j] < A[i-1,k]+W[k+1]+…+W[j] (1)

Значение A[i-1,k] соответствует некоторой подстроке SP[x,k], а значение A[i-1,k1] – подстроке SP[x1,k1], причем x1 > x (иначе не будет выполнено (1)). Таким образом, SP[x1,k1] является подпоследовательностью SP[x,k], причем обе эти строки соответствуют одному и тому же паттерну P[1..i-1]. Это строки различной длины, следовательно этот паттерн содержит хотя бы один символ ‘*’.

Обозначим наибольший индекс символа ‘*’ в P[1..i-1] за q и рассмотрим паттерн P[q..i-1]. В строке SP[x,k] ему соответствует некоторая подстрока SP[y,k], а в строке SP[x1,k1] - SP[y1,k1]. Тогда этому же паттерну соответствует и строка SP[y1, k], а, следовательно, исходному паттерну P[1..i-1] соответствует строка SP[x1, k], причем сложность ее меньше, чем сложность SP[x,k] (так как x1 > x). Это противоречит тому, что A[i-1,k] – это минимальная сложность. Следовательно, значения k1<k, удовлетворяющего (1) не существует.

При решении нам достаточно лишь двух строк A[i-1,…] и A[i, …], следовательно, с памятью проблем не возникает. Пройдясь по всем символам паттерна (индекс i), мы получим массив A[n,…], из которого выберем минимальное значение (среди элементов, не равных -1), которое и будет решением. Если же все элементы этого массива равны -1, то таков и ответ.

Метки:

ACM problems/solutions (SouthEastern European Regional Contest, problem A)
Imagealgrid
Задачи 2009-го года.
http://acm.ro/2009/index.html
http://acm.ro/2009/prob/ACMproblems2009.zip
(копия  http://acm.voroh.com/acm_ro_2009/ACMproblems2009.zip)

Задача A
http://acm.ro/2009/prob/probleme/A.pdf
(копия http://acm.voroh.com/acm_ro_2009/A.pdf )
решение: http://acm.voroh.com/acm_ro_2009/A2009.java


Из условия задачи становится ясно, что условие |q-kp| <= 10^5 должно существенно упростить решение задачи, так как без этого условия задача требует больших вычислительных ресурсов (что, например, обеспечивает стойкость криптографической системы RSA). И действительно, упомянутое неравенство существенно упрощает задачу:

Имеем
n = p*q
p <= q
|q-kp| <= 10^5

Известно n, k
Требуется найти p и q

|q-kp| <= 10^5 перепишем как q-kp = b, |b| <= 10^5
получаем q=kp+b
Отсюда, кстати, следует, что при b>0 числа k и b взаимно простые (хотя я это и не использовал в решении).
Домножим полученное равенство на p:
qp=kp^2+bp
n= kp^2+bp
получаем квадратное уравнение относительно p:
kp^2+bp-n=0

p = (-b±sqrt(b^2+4kn))/2k

Остается перебрать все |b| <= 10^5 и найти такое значение b, для которого мы получим целое p – это и будет искомый результат. Так как при изменении знака b корни уравнения меняют знак, мы можем перебирать значения b от 0 до 10^5, а вычислив значения корня, принимать за p его абсолютную величину.

Верхняя граница для b при небольших n и k может быть уменьшена. Если n/2 + n*k/a < 10^5, то принимаем n/2 + n*k/a за эту границу. Здесь a=up(sqrt(n)), где up – округление вверх до ближайшего целого. Это справедливо, так как p <= q, и, следовательно, |q-kp| < q+kp<= n/2 + k*n/a

Большая часть вычислительных ресурсов уходит на определение, является ли дискриминант b^2+4kn квадратом целого числа. Быстрых алгоритмов проверки этого факта, не требующих вычисления квадратного корня, я не знаю (если знаете - подскажите). Таким образом, приходится вычислять квадратный корень, что занимает значительную часть времени работы программы.

Для решения этой задачи выбрана Java, так как там есть готовая библиотека для работы с большими числами. Я использовал класс BigInteger, который, к сожалению, не поддерживает вычисление квадратного корня (что мне показалось несколько странным – вполне можно было бы реализовать вычисление целой части корня целого числа). Пришлось реализовать эту функцию самому. Для этого использовался алгоритм Ньютона, причем начальное приближение вычислялось как минимальная степень двойки, превышающая sqrt(x). Хороший выбор первого приближения очень важен, так как обеспечивает высокую скорость вычисления требуемого значения.

Возможность применения целочисленной арифметики в методе Ньютона для вычисления квадратного корня, вообще говоря, не очевидна и требует обоснования. Я не вдавался в подробности, но на практике метод работает.

При решении задачи был замечен такой интересный момент – если перебирать значения b в обратном направлении (то есть от 10^5 до 0), то время работы программы увеличивается почти на 2 порядка и составляет более 10 секунд - такой вариант уже вряд ли бы прошел.

Метки:

ACM problems/solutions (SouthEastern European Regional Contest, problem I)
Imagealgrid
Задачи 2009-го года.
http://acm.ro/2009/index.html
http://acm.ro/2009/prob/ACMproblems2009.zip
(копия  http://acm.voroh.com/acm_ro_2009/ACMproblems2009.zip)

Задача I
http://acm.ro/2009/prob/probleme/I.pdf
(копия http://acm.voroh.com/acm_ro_2009/I.pdf )
решение: http://acm.voroh.com/acm_ro_2009/I2009.CPP


Насколько я знаю, такого рода задача может решаться двумя способами: либо перебором, либо методами динамического программирования. Размерность M <= 10^9 сразу навела на мысль, что для динамического программирования явно не хватит памяти. Возможно, тут и есть какие-то перспективы, но я от этого подхода отказался. Ограничение N <= 15, напротив, внушало оптимизм в плане применения перебора. Но все оказалось не так просто. Реализованный «в лоб» перебор работал слишком медленно. Пришлось искать отсечения, которые уменьшили бы дерево поиска.

В процессе поиска поочередно рассматриваем все ящики с алмазами, из каждого выбирается от 0 до k алмазов (как это и определено условием задачи). Применяются отсечения следующего характера:

1. Если в процессе поиска мы приходим к такой ситуации, когда оставшегося свободного места (веса) хватает на все оставшиеся алмазы из нерассмотренных ящиков плюс некоторое количество x алмазов из рассматриваемого в данный момент ящика, то мы забираем все x алмазов из текущего ящика.

2. На каждом из шагов мы оцениваем сверху возможную стоимость выбранных алмазов, и если она меньше текущей максимальной стоимости (полученной ранее), то идти вперед нет смысла, и делается шаг назад. Оценка сверху вычисляется, как произведение оставшегося свободного места (веса) на максимальную удельную стоимость (стоимость делить на вес) алмазов из оставшихся ящиков. Может быть, можно применить и какие-то более сложные и более точные оценки, но я ограничился этой.

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

3. Если для некоторых двух ящиков i и j (считаем, что i<j, и ящики в процессе поиска рассматриваются в порядке возрастания их номеров) выполнено: w[i] <= w[j] и c[i] >= c[j], то брать алмазы из ящика j имеет смысл только тогда, когда уже взято максимальное количество алмазов из ящика i.

4. Если для некоторых двух ящиков i и j (считаем, что i<j, и ящики в процессе поиска рассматриваются в порядке возрастания их номеров) выполнено: w[i] >= w[j] и c[i] <= c[j], и из ящика i взято ненулевое количество алмазов, то брать алмазы из ящика j имеет смысл только все.

В итоге программа на не очень быстрой машине проходит тесты за время около 1,5 секунд. Думаю, что это более-менее удобоваримый результат.

Согласно данным acm.ro , эту задачу на олимпиаде не решила ни одна команда. Думаю, что это не удивительно, потому что, во-первых, я сам решал ее пару дней, имя под рукой тесты :) (хотя это, конечно, не показатель), а во-вторых, абсолютно не факт, что данный перебор с данными отсечениями будет работать за приемлемое время на произвольных входных данных. Но, тем не менее, программа работает, тесты проходит… :)

Метки:

ACM problems/solutions (SouthEastern European Regional Contest, problem K)
Imagealgrid
Задачи 2009-го года.
http://acm.ro/2009/index.html
http://acm.ro/2009/prob/ACMproblems2009.zip
(копия  http://acm.voroh.com/acm_ro_2009/ACMproblems2009.zip)

Задача K
http://acm.ro/2009/prob/probleme/K.pdf
(копия http://acm.voroh.com/acm_ro_2009/K.pdf )
решение: http://acm.voroh.com/acm_ro_2009/K2009.CPP


Решение задачи представляет собой формулу, правда достаточно сложную, со множеством условий. Таблицу, описывающую решение задачи, и доказательство можно найти здесь: http://acm.voroh.com/acm_ro_2009/k_exp.doc Таблица содержит большое количество случаев, так что не исключено, что я что-то пропустил. Тем не менее, тесты программа проходит успешно.
Метки:

Запуск процесса в новой группе процессов.
Imagealgrid
Иногда требуется из shell-скрипта запустить процесс в новой группе процессов. Такая задача может возникнуть, например, если необходимо предотвратить завершение процесса, когда кто-либо (например, родительский процесс интерпретатора) посылает сигнал о завершении всем членам своей группы.

Для этого можно использовать следующую утилитку (привожу исходник на C):

/*
* newpg.c
* Executes a command in a new process group
*/

#include <stdio.h>
#include <unistd.h>


int main(int argc, char *argv[])
{
    setpgrp();
    if (argc > 1) execvp(argv[1], argv+1);
    else printf("Use: newpg cmd\n");
    return 0;
}
Метки: ,

ACM problems/solutions (SouthEastern European Regional Contest, problem C)
Imagealgrid
Задачи 2009-го года.
http://acm.ro/2009/index.html
http://acm.ro/2009/prob/ACMproblems2009.zip
(копия  http://acm.voroh.com/acm_ro_2009/ACMproblems2009.zip)

Задача C
http://acm.ro/2009/prob/probleme/C.pdf
(копия http://acm.voroh.com/acm_ro_2009/C.pdf )
решение: http://acm.voroh.com/acm_ro_2009/c2009.c

Данная задача сводится к задаче о поиске максимального потока в сети. Вершинами в сети (графе) выступают задания (0..n-1) и серверы (n..2n-1). Ребра имеют пропускную способность, равную единице и соединяют задания со способными их выполнить серверами (направление от задания к серверу). Кроме того, добавляем к графу исток и сток. Исток соединяется ребрами с вершинами 0..n-1, а вершины n..2n-1 соединяются со стоком. Максимальная пропускная способность этих ребер также принимается за 1, что соответствует выполнению одной задачи только на одном сервере. Максимальный поток в подобной сети и определит искомое максимальное число одновременно выполняемых заданий.

Алгоритм Форда-Фалкерсона даст нам целые значения потоков через ребра (в нашем случае 0 или 1). Поток, равный 1 через ребро, соединяющее некоторое задание с сервером, говорит о том, что в оптимальной конфигурации данный сервер будет обрабатывать данное задание.

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


Image
Метки:

Image