Динамически генерировать ограниченные решения, которые соответствуют нескольким критериям - PullRequest
0 голосов
/ 26 сентября 2018

Мне кажется, что есть элегантное решение Python для этой проблемы, которое я пытался решить с помощью VBA.Может кто-нибудь помочь, пожалуйста?

Как мне составить список чисел, отвечающих следующим критериям:

  1. Все ли целые числа
  2. Итог сначала делится на типы.
  3. Числа далее разбиваются на подтипы и оптимизируются для соответствия требуемым процентам.
  4. Общая сумма не превышает указанную сумму.

Пример этогозадача:

  • Вы планируете построить максимум 102 жилых дома.
  • Тип строительства: 40% из них - студии, а 60% - строительство таунхаусов.(Может иметь больше или меньше типов)
  • Существует два Приоритета списков для будущих жителей квартир: Сопровождаемые и без посторонней помощи
    • Единицапроценты распределения в списке Assisted (A) должны быть полностью выполнены, а список Unassisted (U) является гибким.Мы бы хотели, чтобы список «Без посторонней помощи» (U) составлял до 20% от общего количества юнитов, если это возможно, но нам определенно нужно минимум 80% от общего количества юнитов, которым будут помогать (A).
  • Вспомогательные (A) единицы составляют всего 102x80% = 81,6 единиц (уже не целое число)
    • Минимум 10% от Assisted (A)Единицы списка должны быть для лиц пожилого возраста.
    • Минимум 40% единиц списка Assisted (A) должны быть для семей.
    • Остальные 50% единиц списка Assisted (A)для начинающих ученых данных.

Оставшиеся 20% от общего количества единиц - это свободные места (U).

Итак:

  • Всего: 102 единицы.
  • Construction_type_categories=[.4, .6] (102 единицы разделены на студии и таунхаусы: 40% и 60%)
  • Assisted=[.1,.4,.5] (80% + от общего числа единиц Помощи, далее классифицируются как пожилые, семьи, другие занятия в соответствии с процентами в списке)
  • Части без посторонней помощи являются оставшимися единицами, которые не были частью80% + списка Assisted.(до 20% от общего количества единиц)

Результат:

[4,16,12,8,7,25,19,11]

Разбивка:

  • 4 студийных блока Помощь для пожилых людей
  • 16 студийных единиц Помощь для семей
  • 12 студийных единиц для других типов вспомогательных занятий
  • 8 студийных единиц (без посторонней помощи)
  • 7 таунхаусов для пожилых людей
  • 25 единиц таунхаусов для семей
  • 19 единиц таунхаусов для других типов вспомогательных помещений
  • 11 единиц таунхаусов (без посторонней помощи).

Сначала я подумал о созданииПредварительный массив округленных чисел, а затем цикл и внесение корректировок.Это выглядело так утомительно, что я начал задумываться о создании большой матрицы чисел с использованием numpy и фильтрации по указанным критериям.

Создание и оптимизация чисел вручную занимало много времени, поэтому я признателен за любую помощь в поиске лучшего решения.

import math

def is_even(x):
    if x % 2 == 0:
        return True
    else:
        return False

total=102 
unassisted=.2
unassisted_unit_count= math.floor(total*unassisted)
assisted_unit_count=total- unassisted_unit_count

construction_type_categories=[.4, .6] #Must be even.
assisted_subcategories=[.1,.4,.5] #Last element here will be of least priority.


def Unit_Number_Getter(L):

    if L[1]=='total_constr_type_amounts':
        giventotal= total
    if L[1]=='assisted_constr_type_amounts':
        giventotal= assisted_unit_count

    #Spliting by construction type (preliminary).
    constr_type_amounts=[]
    for ct in construction_type_categories:
        constr_type_amounts.append(round(giventotal * ct))

    #Making the unit counts even for the total construction type amounts (need to).
    for p in constr_type_amounts:
        if not is_even(p):
            add_here=constr_type_amounts.index(p)
            for f in constr_type_amounts:
                if not is_even(f):
                    from_here= constr_type_amounts.index(f)
            constr_type_amounts[add_here] +=1
            constr_type_amounts[from_here] -=1
    assert sum(constr_type_amounts)==giventotal

    print L[1]
    print(constr_type_amounts)
    L[0]=constr_type_amounts


total_constr_type_amounts=0
assisted_constr_type_amounts=0

List_of_lists=[[total_constr_type_amounts,"total_constr_type_amounts"],[assisted_constr_type_amounts,"assisted_constr_type_amounts"]]

#Established the unit counts for each construction type (for Assisted and total units)
for L in List_of_lists:
    Unit_Number_Getter(L)


#Getting a list of the unit counts for each assisted subcategory in each constr type.
testlist=[]
for c in List_of_lists[1][0]:
    already_added=0
    for a in assisted_subcategories[:-1]:
        adding_now= math.ceil(c * a)
        testlist.append(adding_now)
        already_added+=adding_now
    #^Added the priority assisted units (all but the last element).   

    #Now will add the last of the assisted units.
    testlist.append(c-already_added)

    #Now will add he least prioritized unassisted units up to the max.
    Max_unassisted_units= List_of_lists[0][0][List_of_lists[1][0].index(c)]-c

    testlist.append(Max_unassisted_units)

    assert ((c+Max_unassisted_units)== List_of_lists[0][0][List_of_lists[1][0].index(c)])#all units present

print("Result: "+ "\n" + str(testlist))     
...