Cheklovni kamaytiradigan optimal echim topish?

Ushbu muammoni Slinger-Bird muammosiga (aslida Slinger serverga o'xshash va qushni so'rash uchun chaqiramiz, lekin bu haqda o'ylayman, shuning uchun men boshqacha nuqtai nazarga ega bo'lish umidida o'zgardi).

  • S tosh otishgichlari (slingers) va B qushlari mavjud.
  • Slingerlar bir-birining oralig'ida emas.
  • Slinging bir marta butun bir qushni slingerning ko'z oldida o'ldirishi va bir martalik va bir martalik birlikni ishlatishi mumkin

Men parranda parrandalari qushlarni yo'q qilish uchun kerak bo'lgan tortishish vaqtini va sonini kamaytiradigan optimal echimini topishga harakat qilaman. Mutlaq raqamlarga misol keltiray: 3 slinger va 4 qush.

        Time        1            2            3           4             5
Slinger
S1                B1, B2     B1, B2, B3       B4
S2                               B1         B1, B2      B3,B4     
S3                  B1         B3, B4                 B1,B2,B3,B4

va mening ma'lumotlarim shunday ko'rinadi:

>> print t
[
  {
    1: {S1: [B1, B2], S2: [], S3: [B1]}, 
    2: {S1: [B1, B2, B3], S2: [B1], S3: [B3, B4]},
    3: {S1: [B4], S2: [B1,B2], S3: []},
    4: {S1: [], S2: [B3, B4], S3: [B1, B2, B3, B4]}
  }
]

Men o'ylayotgandek bir necha echim bor (T = k da Sx, slinger Sx vaqtida otishni o'rganish degan ma'noni anglatadi):

  1. S1 at t=1, S1 at t=2, S1 at t=3 <- Cost: 3 shots + 3 time units = 6
  2. S1 at t=2, S1 at t=3 <- Cost: 2 shots + 3 time units = 5
  3. S1 at t=1, S3 at t=2 <- Cost: 2 shots + 2 time units = 4
  4. S3 at t=4 <- Cost: 1 shot + 4 time units = 5

Buning uchun men uchun 3 yechimining eng maqbul varianti ko'rinadi. Albatta, men buni qo'l bilan qildim (shuning uchun men bir narsani qoldirib ketgan bo'lishim mumkin), lekin buni amalga oshirishning keng ko'lamli usuli haqida o'ylay olmayman. Bundan tashqari, men burchak uradi borligi uchun tashvishlanyapman, chunki bitta otishni o'rganish qarori boshqalarning qarorini o'zgartirishi mumkin, lekin men global nuqtai nazarga ega bo'lgani uchun bu muhim emas.

Pythonda ushbu muammoni hal qilishning tezkor va yaxshi yo'li nima? Buni amalga oshirish uchun algoritmni yolg'iz qoldirish uchun yaxshi ma'lumot strukturasi bilan kelishib olish qiyin kechmoqda. Men dinamik dasturlardan foydalanishni o'ylayapman, chunki bu davlat makonini qidirishni o'z ichiga oladi, ammo qanday davom etishi haqida bir oz chalkashtiraman. Har qanday taklif bormi?

7
@mhum: Bu haqda ko'proq fikr yuritish, men bu muammoni aslida vaqtni tushunish va har bir to'siqqa xarajat funksiyasini qo'shish orqali minimal to'siqni kodlash mumkin deb o'ylayman. Albatta, men bu savolga slingerni qanday kodlashni bilmayman. Ushbu yondashuv bo'yicha biron-bir taklifingiz bormi?
qo'shib qo'ydi muallif Legend, manba
Malumot uchun: Faqat bir vaqt ichida muammoingiz Minimal Set Cover ga mos keladi.
qo'shib qo'ydi muallif mhum, manba

3 javoblar

Bu eng yaxshi vazifa emas, chunki slingerlar barcha qushlarni ko'zdan kechirishadi.

Sizda ikki o'lchovli ob'ektiv funktsiyasi mavjud, shuning uchun tortishish va vaqt oralig'ida bir nechta kelishmovchiliklar bo'lishi mumkin. Muayyan vaqt uchun tortishishning minimal sonini aniq belgilash aniq to'siq muammosidir (mam taklif qiladi). O'rnatilgan qopqoqning muammoni NP-qattiq va taxminan taxmin qilish qiyin, lekin amalda, chiziqli dasturiy formulasini juftligini qo'llagan holda, filial va bog'lanish optimallikni aniqlashda juda samarali.

4
qo'shib qo'ydi
+1 Maslahat uchun rahmat. Men LP mutaxassisi emasman, lekin bu masalani kodlashda tortib olaman. Buni yuqorida fikr deb yozgan edim, lekin vaqt tushunchasini yo'qotish va har bir hujayra o'rniga xarajat vazifasini qo'shish haqida o'ylayman. Ammo, men aytib o'tganimdek, uni qanday shakllantirish borasida men aniq bilmayman.
qo'shib qo'ydi muallif Legend, manba

Men slingers va qushlar uchun bitmaplardan foydalanishni taklif qilaman, ya'ni.

S1 = B1 = 1, S2 = B2 = 2, S3 = B3 = 4, B4 = 8

Keyin kirish ma'lumotlari quyidagicha yozilishi mumkin

bird_data = [[3, 0, 1], [7, 1, 12], [8, 3, 0], [0, 12, 15]]

Xost funksiyasi endi shunday yozilishi mumkin:

def cost(shots):
    hit = units = 0
    for show, shot in zip(bird_data, shots):
        units += 1
        for n, birds in enumerate(show):
            if shot & 1:
                units += 1
                hit |= birds
                if hit == 15: # all are hit
                    return units
            shot >>= 1
    return 99 # penalty when not all are hit

Endi eng kam qiymatni hisoblash yo'li bilan maqbul tortishishlarni topish oson:

from itertools import product

shot_sequences = product(*([range(7)]*len(bird_data)))

print min((cost(shots), shots) for shots in shot_sequences)

Ushbu bosib chiqaradi

(4, (0, 5, 0, 0))

ya'ni S1 va S3 (5 = 1 + 4) t = 2 da yong'in chiqqanda tegmaslik 4 birlikni bildiradi. Albatta sizning echimingiz ham mumkin, bu erda S1 t = 1 va S3 da t = 2 da yonganda, har ikkalasi bir xil xarajatlarga ega.

Biroq, algoritm barcha qo'zg'aluvchan ketma-ketliklar ustida ishlaydigan qo'pol kuch ishlatganligi uchun, ma'lumotlar to'plamlari sizning namunangizdagidek juda tez va qulaydir.

1
qo'shib qo'ydi
Buning uchun rahmat. Men kodlashni yaxshi tushunganimga ishonchim komil emas, lekin unga yana bir marta urinaman. Bir qarashda, buni amalga oshirish mumkin bo'lmasligi mumkin, chunki mening asosiy muammomda vaqtning uzunligi taxminan 10000ni tashkil etadi.
qo'shib qo'ydi muallif Legend, manba

Men algoritmni boshlaganingizda namunadagi barcha raqamlarni bilasiz va t1ni tugatgandan so'ng t2 ni topa olmaysiz.

Bundan tashqari, ikkita slinger bir vaqtning o'zida yong'in chiqishi mumkinligini taxmin qilaman.

Birinchi tanlovda siz har bir xonaga qiymati, ya'ni miqdoriOdBirdsInCell-time sifatida belgilashingiz mumkin.

Bu sizga S1t1, S1t2, qolganlari past bo'lgan qiymatlar bilan ikkita hujayra beradi.

Sizning hisobingizdagi so'nggi hujayra faqatgina vaqtni hisoblab chiqadi, shuning uchun dastlabki tanlovni keyingi bosqichga o'tkazish vaqtni eng qimmatli vaqtga aylantiradi. Bu birinchi tanlov.

Endi barcha hujayralardagi birinchi tanlovda o'ldirilgan qushlarni olib tashlang.

Qolgan hujayralar uchun qiymatni aniqlash jarayonini takrorlang. Sizning namunangizda S3t2 hujayrasi eng yuqori natijani beradi, 0 bo`ladi.

Ushbu jarayonni takrorlab, eng qadrli hujayralarni eng qadimgi davrlarda olasiz.

Sizning misolingizdan biri muhim emas: Agar sizning eng qimmatli tanlovingiz t2da bo'lsa, keyingi eng qimmatli tanlov t1 yoki t2 da bo'lishi mumkin, shuning uchun ularni hisobga olish kerak. Biroq, t2 allaqachon tasdiqlangani uchun ularning qiymatlarini hisobga olish kerak emas.

Men hech qachon pythonda yozmaganman, algoritm yorlig'i tufayli bu yerga keldim, shuning uchun java/c kabi pseudo kodi bor:

highestCellTime = 0;
while(birdsRemain)
{
    bestCell;

    for(every cell that has not been picked yet)
    {
        currentCellValue = amountOfBirds;
        if(currentCellTime > highestCellTime)
        {
            currentCellValue = currentCellValue - currentCellTime;
        }

        if(currentCellValue < bestCellValue)
        {
            bestCell = thisCell;
        }
        else if(currentCellValue == bestCellValue && currentCellTime < bestCellTime)
        {
            bestCell = thisCell;
        }
    }
    addCellToPicks(bestCell);
    removeBirdsFromOtherCells(bestCellBirds);
}

Agar biror narsani esdan chiqarmasam, sizning tanlovingizdagi hujayralaringizning optimal kombinatsiyasi mavjud.

Umid qilamanki, bu kod python dasturchilar uchun mantiqan. Agar kimdir uni tarjima qila olsa, iltimos! Va iltimos, matnning bu bitini va java/c-pseudocode oldingi eslatmasini olib tashlang.

EDIT by OP: First version and does not end up with the best cells. I am guessing it must be a bug in my code but nevertheless I am posting here.

import math

cellsNotPicked = range(0,12)
cellToBird = {
    0: [1, 2],
    1: [],
    2: [1],
    3: [1,2,3],
    4: [1],
    5: [3,4],
    6: [4],
    7: [1,2],
    8: [],
    9: [],
    10: [3,4],
    11: [1,2,3,4]
}

picks = []

def getCellValue(cell):
    return len(cellToBird[cell])

def getCellTime(cell):
    return int(math.floor(cell/3)) + 1

birdsRemain = 4

while(birdsRemain > 0):

    bestCell = 0;

    for thisCell in cellsNotPicked:

        currentCellValue = getCellValue(thisCell);

        currentCellTime = getCellTime(thisCell)
        highestCellTime = getCellTime(bestCell)

        if(currentCellTime > highestCellTime):
            currentCellValue = currentCellValue - currentCellTime;

        if(currentCellValue < getCellValue(bestCell)):
            bestCell = thisCell
        elif (currentCellValue == getCellValue(bestCell)) and (currentCellTime < getCellTime(bestCell)):
            bestCell = thisCell

    picks.append(bestCell)
    cellsNotPicked.remove(bestCell)

    birdsToRemove = cellToBird[bestCell]

    for key in cellToBird:
        for bird in birdsToRemove:
            try:
                cellToBird[key].remove(bird)
                birdsRemain -= 1
            except:
                pass

print picks
1
qo'shib qo'ydi
+1 Birinchidan, vaqt uchun rahmat. Algoritmni haqiqiy kodga aylantirdim, lekin, albatta, mening kodimdagi xatolik bo'lishi mumkin, chunki menga bergan javob [9,10] hujayralar sifatida tanlanadi. Hozirda disk raskadrovka qilishga harakat qilaman va u bilan nima noto'g'ri ekanini bilsam, uni qaytarib beraman. Kodning o'zi tushunish uchun juda ahamiyatsiz va algoritmda foydalanganingizdek bir xil so'zlarni ishlatishga harakat qildim, shunda biz umumiy tilni gapirishimiz mumkin :)
qo'shib qo'ydi muallif Legend, manba
@Legend Xush kelibsiz, jumboq uchun rahmat! Bu juda qiziq. Yaxshiyamki, men kodni bir necha marta chopib tashladim, 9-hujayraning maxsus nima ekanligini bilmayman. Qaysi birini birinchi topasiz? Aytgancha, siz qushlarni tushirmoqdasiz deb o'ylaysiz. O'zingiz chiqargan har bir takrorlangan qush uchun 1-baho bering. Qaysi 9 ni birinchi marta olgandan shubha qilsa, hech qanday qushni olib tashlamaydi, keyin 10 ni oladi, bu summani 2 ga olib keladi. Lekin, ehtimol, men hali Python kodini yaxshi tushunolmayman. ^^ '
qo'shib qo'ydi muallif Aberrant, manba
Python
Python
372 ishtirokchilar

Bu guruh python dasturlash tilini muhokama qilish uchun. Iltimos, o'zingizni hurmat qiling va faqat dasturlash bo'yicha yozing. Botlar mavzusini @botlarhaqida guruhida muhokama qling! FAQ: @PyFAQ Offtopic: @python_uz_offtopic

Python offtopic group !
Python offtopic group !
150 ishtirokchilar

@python_uz gruppasining offtop gruppasi. offtop bo'lsa ham reklama mumkin emas ) Boshqa dasturlash tiliga oid gruppalar @languages_programming