Оптимизация декартовых запросов с аффинными затратами

Считайте Запрос. Сформируйте NameValueCollection и обработайте Вашу логику соответственно:

NameValueCollection nvc = Request.Form;
string userName, password;
if (!string.IsNullOrEmpty(nvc["txtUserName"]))
{
  userName = nvc["txtUserName"];
}

if (!string.IsNullOrEmpty(nvc["txtPassword"]))
{
  password = nvc["txtPassword"];
}

//Process login
CheckLogin(userName, password);

..., где "txtUserName" и "txtPassword" Имена из средств управления на странице регистрации.

9
задан LeMiz 10 September 2009 в 09:13
поделиться

6 ответов

Выбор подматриц для покрытия запрошенных значений является формой задачи покрытия набора и, следовательно, NP-завершенной. Ваша проблема добавляет к этой и без того сложной проблеме то, что стоимость наборов различается.

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

В статье в Википедии приводятся результаты о несовместимости, заключающиеся в том, что задача не может быть решена за полиномиальное время лучше, чем с коэффициентом 0,5 * log2 (n) , где n - количество наборов. В вашем случае 2 ^ (n * p) является (довольно пессимистичным) верхним пределом для количества наборов и выходов, решение которого можно найти только с коэффициентом 0,5 * n * p за полиномиальное время (помимо N = NP и игнорирования переменных затрат).

Оптимистическая нижняя граница для количества наборов, игнорирующих перестановки строк и столбцов, составляет 0,5 * n ^ 2 * p ^ 2 дает гораздо лучший коэффициент log2 (n) + log2 (p) - 0,5 . Следовательно, вы можете рассчитывать найти решение только в худшем случае n = 1000 и p = 200 с коэффициентом примерно 17 в оптимистическом случай и с коэффициентом примерно 100000 в пессимистическом случае (все еще игнорируя различные затраты).

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

000 в пессимистическом случае (все еще игнорируя различные затраты).

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

000 в пессимистическом случае (все еще игнорируя различные затраты).

Лучшее, что вы можете сделать, - это использовать эвристический алгоритм (статья в Википедии упоминает почти оптимальный жадный алгоритм) и согласиться с тем, что будет случай, когда алгоритм работает (очень) плохо. Или вы идете другим путем, используете алгоритм оптимизации и пытаетесь найти хорошее решение, тратя больше времени. В этом случае я бы предложил попробовать использовать A * search .

5
ответ дан 4 December 2019 в 23:06
поделиться

Хорошо, мое понимание вопроса изменилось. Новые идеи:

  • Храните каждую строку как длинную битовую строку. И пары битовых строк вместе, пытаясь найти пары, которые максимизируют количество 1 бит. Разрастите эти пары в большие группы (отсортируйте и попытайтесь сопоставить действительно большие группы друг с другом). Затем создайте запрос, который попадет в самую большую группу, а затем забудьте обо всех этих битах. Повторяйте, пока все не будет сделано. Может быть, иногда переключаться со строк на столбцы.

  • Ищите все строки / столбцы с нулевым или небольшим количеством точек в них. «Удалите» их временно. Теперь вы смотрите на то, что может быть покрыто запросом, который их не учитывает. Теперь, возможно, примените один из других методов, а потом разберетесь с проигнорированными строками / столбцами. Другой способ подумать об этом: сначала разберитесь с более плотными точками, а затем переходите к более разреженным.

1
ответ дан 4 December 2019 в 23:06
поделиться

Поскольку ваши значения скудны, может ли случиться так, что многие пользователи запрашивают похожие значения? Возможно ли кеширование в вашем приложении? Запросы можно индексировать с помощью хэша, который является функцией позиции (x, y), чтобы вы могли легко идентифицировать кэшированные наборы, которые попадают в правильную область сетки. Хранение кэшированных наборов в дереве, например, позволит вам очень быстро найти минимальные кэшированные подмножества, которые охватывают диапазон запросов. Затем вы можете выполнить линейный поиск по небольшому подмножеству.

0
ответ дан 4 December 2019 в 23:06
поделиться

Я бы рассмотрел n записей (строк) и p полей (столбцов), упомянутых в запросе пользователя, установленным как n точек в p-мерном пространстве ({0,1} ^ p) с i-я координата равна 1, если у нее есть X, и идентифицируют иерархию кластеров , с самым грубым кластером в корне, включая все X. Для каждого узла в иерархии кластеризации рассмотрите продукт, который охватывает все необходимые столбцы (это строки (любой подузел) x столбцы (любой подузел)). Затем решите снизу вверх, объединять ли дочерние покрытия (оплачивая все покрытие) или оставить их как отдельные запросы. (покрытия сделаны не из смежных столбцов, а именно из тех, которые необходимы; например, подумайте о битовом векторе)

Я согласен с Артелиусом, что перекрывающиеся запросы продуктов могут быть дешевле;

0
ответ дан 4 December 2019 в 23:06
поделиться

Я уверен, что где-то есть действительно хороший алгоритм для этого, но вот мои собственные интуитивные идеи:

  1. Подход «бросай прямоугольники»:

    • Определить «примерно оптимальный "размер прямоугольника на основе a .
    • Поместите эти прямоугольники (возможно, случайным образом) над вашими необходимыми точками, пока все точки не будут покрыты.
    • Теперь возьмите каждый прямоугольник и сожмите его как можно больше без "потеря" любых точек данных.
    • Найдите прямоугольники, расположенные близко друг к другу, и решите, будет ли их объединение дешевле, чем их разделение.
  2. Рост

    • Начните с каждой точки в своем собственном прямоугольнике 1x1.
    • Найдите все прямоугольники в пределах n строк / столбцов (где n может быть основано на a ); посмотрите, сможете ли вы объединить их в один прямоугольник бесплатно (или с отрицательной стоимостью: D).
    • Повторите.
  3. Сжатие

    • Начните с одного большого прямоугольника, который покрывает ВСЕ точки.
    • Ищите подпрямоугольник, который имеет общую пару сторон с большой, но содержит очень мало точек.
    • Обрежьте его. из большого, получится два меньших прямоугольника.
    • Повторить.
  4. Quad

    • Разделите плоскость на 4 прямоугольника. Для каждого из них посмотрите, получите ли вы лучшую стоимость, продолжая рекурсию или просто включая весь прямоугольник.
    • Теперь возьмите свои прямоугольники и посмотрите, сможете ли вы объединить любые из них с небольшими затратами / бесплатно. \

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

  • Найдите подпрямоугольник, у которого есть пара сторон с большим, но очень мало точек.
  • Вырежьте его из большого прямоугольника, получив два меньших прямоугольника.
  • Повторите.
  • Quad

    • Разделите плоскость на 4 прямоугольника. Для каждого из них посмотрите, получите ли вы лучшую стоимость, продолжая рекурсию или просто включая весь прямоугольник.
    • Теперь возьмите свои прямоугольники и посмотрите, сможете ли вы объединить любые из них с небольшими затратами / бесплатно. \
  • Также: имейте в виду , что иногда будет лучше иметь два перекрывающихся прямоугольника, чем один большой прямоугольник, который является их надмножеством. Например, в случае, когда два прямоугольника просто перекрываются в одном углу.

  • Найдите подпрямоугольник, у которого есть пара сторон с большим, но очень мало точек.
  • Вырежьте его из большого прямоугольника, получив два меньших прямоугольника.
  • Повторите.
  • Quad

    • Разделите плоскость на 4 прямоугольника. Для каждого из них посмотрите, получите ли вы лучшую стоимость, продолжая рекурсию или просто включая весь прямоугольник.
    • Теперь возьмите свои прямоугольники и посмотрите, сможете ли вы объединить любые из них с небольшими затратами / бесплатно. \
  • Также: имейте в виду , что иногда будет лучше иметь два перекрывающихся прямоугольника, чем один большой прямоугольник, который является их надмножеством. Например, в случае, когда два прямоугольника просто перекрываются в одном углу.

  • Quad

    • Разделите плоскость на 4 прямоугольника. Для каждого из них посмотрите, получите ли вы лучшую стоимость, продолжая рекурсию или просто включив весь прямоугольник.
    • Теперь возьмите свои прямоугольники и посмотрите, сможете ли вы объединить любой из них с небольшими / бесплатными затратами. \
  • Также: имейте в виду , что иногда будет лучше иметь два перекрывающихся прямоугольника, чем один большой прямоугольник, который является их надмножеством. Например, в случае, когда два прямоугольника просто перекрываются в одном углу.

  • Quad

    • Разделите плоскость на 4 прямоугольника. Для каждого из них посмотрите, получите ли вы лучшую стоимость, продолжая рекурсию или просто включая весь прямоугольник.
    • Теперь возьмите свои прямоугольники и посмотрите, сможете ли вы объединить любые из них с небольшими затратами / бесплатно. \
  • Также: имейте в виду , что иногда будет лучше иметь два перекрывающихся прямоугольника, чем один большой прямоугольник, который является их надмножеством. Например, в случае, когда два прямоугольника просто перекрываются в одном углу.

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

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

    1
    ответ дан 4 December 2019 в 23:06
    поделиться

    Я немного поработал над этим, и вот очевидный, O (n ^ 3) жадный алгоритм нарушения симметрии (записи и поля обрабатываются отдельно) в псевдо- code.

    Идея тривиальна: мы начинаем с проверки одного запроса на запись и выполняем наиболее подходящее слияние, пока не останется ничего, достойного слияния. У этого алгоритма есть очевидный недостаток, заключающийся в том, что он не позволяет перекрывать запросы, но я ожидаю, что он будет работать достаточно хорошо в реальном случае (с a + n * (p ^ b) + c * n * p * (1 - g) функция стоимости):

    # given are
    # a function cost request -> positive real
    # a merge function that takes two pairs of sets (f1, r1) and (f2, r2) 
    # and returns ((f1 U f2), (r1 U r2))
    
    # initialize with a request per record
    
    requests = [({record},{field if (record, field) is needed}) for all needed records]
    costs = [cost(request) for request in requests]
    
    finished = False
    
    while not finished: # there might be something to gain
        maximum_gain = 0
        finished = True
        this_step_merge = empty
    
        # loop onto all pairs of request
        for all (request1, request2) in (requests x request) such as request1 != request2:
            merged_request = merge(request1, request2)
            gain = cost(request1) + cost(request2) - cost(merged_request)
    
            if gain > maximum_gain:
                maximum_gain = gain
                this_step_merge = (request1, request2, merged_request)
    
        # if we found at least something to merge, we should continue
        if maximum_gain > 0:
            # so update the list of requests...
            request1, request2, merged_request = this_step_merge
            delete request1 from requests
            delete request2 from requests
            # ... and we are not done yet
            insert merged_request into requests
            finished = False
    
    output requests
    

    Это O (n3 * p), потому что:

    • после инициализации мы начинаем с n запрашивает
    • , а цикл удаляет ровно один запрос из пула на каждой итерации.
    • внутренний цикл for выполняет итерацию по ( ni ^ 2 - ni ) / 2 различных парах запросов, причем ni изменяется от n до единицы в худшем случае (когда мы объединить все в одну большую просьбу).

      1. Может ли кто-нибудь помочь мне указать на очень плохие случаи алгоритма. Звучит разумно использовать это?
      2. Это O (n ^ 3), что слишком дорого для больших вложений. Есть идеи по оптимизации?

    Заранее благодарим!

    0
    ответ дан 4 December 2019 в 23:06
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: