mall-tenant problem: the idealist and the...

13
Makalah IF2120 Matematika Diskrit Sem. I Tahun 2017/2018 Mall-Tenant problem: The Idealist and The Greed Jessin Donnyson 13516112 Program Studi Teknik Informatika Sekolah Teknik Elektro dan Informatika Institut Teknologi Bandung, Jl. Ganesha 10 Bandung 40132, Indonesia [email protected] AbstractDalam makalah ini digambarkan sebuah permasalahan dunia nyata dimana sebuah mall akan disewakan ke sejumlah tenant. Pemilihan tenant menjadi poin penting bagi pengembang untuk memaksimalkan profit. Permasalahan bukan sekedar knapsack problems biasa, melainkan ekstensifikasi dimana dimensi ‘profit’, ‘bag’ dan ‘weight’ yang terdefinisi, lebih dari satu dimensi (multidimensional knapsack problem). Makalah akan membahas pendekatan pemilihan tenant yang bisa disimulasikan dengan berbagai paradigma pemrograman: khususnya dynamic programming dan greedy approach. KeywordsDynamic Programming, Greedy approach, Knapsack problems, Multidimensional knapsack problem, paradigma pemrograman. I. PENGANTAR Dalam kehidupan, kadang kita dipertemukan dengan permasalahan penyusunan dan pemilihan suatu benda atau komponen, dengan berbagai tujuan dan target yang ingin dicapai. Dalam kasus ini, bisa saja setiap benda memiliki nilai keuntungan dan penggunaan ‘resource’ yang berbeda, dan kita harus memilih dan mencoba membandingkan semua kemungkinan kombinasi supaya menghasilkan nilai keuntungan maksimal. Salah satu contoh permasalahan konkrit adalah proses memilih penyewa yang akan menyewa slot / kios dalam suatu pusat perbelanjaan (mal). Pengembang akan berusaha semaksimal mungkin untuk mencari penyewa yang akan mendatangkan keuntungan terbesar untuk mal tsb. baik dari segi meningkatkan pemasukan dan berbagai aspek lainnya. Pada makalah ini, akan disimulasikan bagaimana dari daftar penyewa, dipilih kombinasi penyewa yang menghasilkan profit maksimum sesuai kebutuhan pengembang dengan mempertimbangkan slot (ukuran ruang yang disewakan) yang tersedia dalam mal. Supaya lebih realistis, profit yang dihasilkan tidak hanya berupa profit dalam hal uang, namun misal kontribusi pengunjung, rating mal, dll. Sebelum membahas simulasi yang digunakan, beberapa landasan teori yang dibutuhkan adalah Dynamic programming, Greedy approach, dan Knapsack problems. II. DYNAMIC PROGRAMMING Dynamic Programming atau pemrograman dinamis, adalah suatu paradigma algoritma, dimana sebuah permasalahan kompleks, dapat dipecah menjadi beberapa sub-masalah, yang dapat diselesaikan lebih mudah, dan hasilnya dicatat untuk menghindari adanya proses komputasi ulang [1]. Salah satu properti dari pemrograman dinamis adalah pemecahan masalah menjadi sub-masalah (seperti dalam pendekatan divide and conquer) dan terutama digunakan apabila komputasi yang sama akan dilakukan berulang-ulang. Hal ini mengimplikasi bahwa pemrograman dinamis tidak cocok dilakukan jika tidak ada sub-permasalahan yang dapat dipakai kembali (pencatatan hasil menjadi sia-sia). Keuntungan digunakannya pemrograman dinamis dibandingkan dengan pendekatan greedy adalah dalam pemrograman dinamis, hasil optimum global dapat dijamin, dan jika ada lebih dari satu solusi, kemungkinan besar dapat ditunjukan oleh pemrograman dinamis. Walaupun untuk kebanyakan permasalahan, pendekatan greedy dapat memberikan komputasi yang sangat cepat dan mendekati hasil optimum global [2, 3]. A. Memoization Salah satu penerapan pemrograman dinamis adalah dengan memoization, yaitu mencoba mencari hasil yang diharapkan dari ‘memo’ atau data container yang tersedia. Jika tidak tersedia, baru dilakukan komputasi, dan hasilnya dicatat dalam ‘memo’ tsb. supaya dapat digunakan untuk proses selanjutnya jika diperlukan. Keuntungan metode ini adalah pencatatan hanya dilakukan jika diperlukan (on demand) [1]. B. Tabulation Pendekatan lainnya adalah dengan tabulasi, yaitu membuat tabel dari sub-permaslahan paling sederhana, sampai yang paling kompleks. Kemudian jika diperlukan, cukup mengakses hasil yang sudah dikomputasi terlebih dahulu. Dalam pendekatan ini, semua kemungkinan akan dicoba dan dicatat hasil komputasinya [1]. III. GREEDY APPROACH Paradigma pendekatan greedy adalah suatu paradigma algoritma dimana dengan memanfaatkan heuristic, mencari opsi / pilihan optimum lokal, dengan harapan akan menghasilkan optimum global pada akhirnya [4]. Secara umum, pendekatan greedy tidak akan menghasilkan solusi optimum global, namun kenyataanya pada kebanyakan permasalahan, dapat menghasilkan solusi yang menghampiri optimum global, (dengan mengambil optimum lokal pada setiap tahapnya) dan yang terpenting: dengan kompleksitas waktu yang sangat minimum.

Upload: danganh

Post on 14-Jun-2019

232 views

Category:

Documents


0 download

TRANSCRIPT

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

Mall-Tenant problem: The Idealist and The Greed

Jessin Donnyson 13516112

Program Studi Teknik Informatika

Sekolah Teknik Elektro dan Informatika

Institut Teknologi Bandung, Jl. Ganesha 10 Bandung 40132, Indonesia

[email protected]

Abstract—Dalam makalah ini digambarkan sebuah

permasalahan dunia nyata dimana sebuah mall akan disewakan ke

sejumlah tenant. Pemilihan tenant menjadi poin penting bagi

pengembang untuk memaksimalkan profit. Permasalahan bukan

sekedar knapsack problems biasa, melainkan ekstensifikasi dimana

dimensi ‘profit’, ‘bag’ dan ‘weight’ yang terdefinisi, lebih dari satu

dimensi (multidimensional knapsack problem). Makalah akan

membahas pendekatan pemilihan tenant yang bisa disimulasikan

dengan berbagai paradigma pemrograman: khususnya dynamic

programming dan greedy approach.

Keywords—Dynamic Programming, Greedy approach,

Knapsack problems, Multidimensional knapsack problem,

paradigma pemrograman.

I. PENGANTAR

Dalam kehidupan, kadang kita dipertemukan dengan

permasalahan penyusunan dan pemilihan suatu benda atau

komponen, dengan berbagai tujuan dan target yang ingin

dicapai. Dalam kasus ini, bisa saja setiap benda memiliki nilai

keuntungan dan penggunaan ‘resource’ yang berbeda, dan kita

harus memilih dan mencoba membandingkan semua

kemungkinan kombinasi supaya menghasilkan nilai keuntungan

maksimal.

Salah satu contoh permasalahan konkrit adalah proses

memilih penyewa yang akan menyewa slot / kios dalam suatu

pusat perbelanjaan (mal). Pengembang akan berusaha

semaksimal mungkin untuk mencari penyewa yang akan

mendatangkan keuntungan terbesar untuk mal tsb. baik dari segi

meningkatkan pemasukan dan berbagai aspek lainnya.

Pada makalah ini, akan disimulasikan bagaimana dari daftar

penyewa, dipilih kombinasi penyewa yang menghasilkan profit

maksimum sesuai kebutuhan pengembang dengan

mempertimbangkan slot (ukuran ruang yang disewakan) yang

tersedia dalam mal.

Supaya lebih realistis, profit yang dihasilkan tidak hanya

berupa profit dalam hal uang, namun misal kontribusi

pengunjung, rating mal, dll.

Sebelum membahas simulasi yang digunakan, beberapa

landasan teori yang dibutuhkan adalah Dynamic programming,

Greedy approach, dan Knapsack problems.

II. DYNAMIC PROGRAMMING

Dynamic Programming atau pemrograman dinamis, adalah

suatu paradigma algoritma, dimana sebuah permasalahan

kompleks, dapat dipecah menjadi beberapa sub-masalah, yang

dapat diselesaikan lebih mudah, dan hasilnya dicatat untuk

menghindari adanya proses komputasi ulang [1].

Salah satu properti dari pemrograman dinamis adalah

pemecahan masalah menjadi sub-masalah (seperti dalam

pendekatan divide and conquer) dan terutama digunakan apabila

komputasi yang sama akan dilakukan berulang-ulang. Hal ini

mengimplikasi bahwa pemrograman dinamis tidak cocok

dilakukan jika tidak ada sub-permasalahan yang dapat dipakai

kembali (pencatatan hasil menjadi sia-sia).

Keuntungan digunakannya pemrograman dinamis

dibandingkan dengan pendekatan greedy adalah dalam

pemrograman dinamis, hasil optimum global dapat dijamin, dan

jika ada lebih dari satu solusi, kemungkinan besar dapat

ditunjukan oleh pemrograman dinamis. Walaupun untuk

kebanyakan permasalahan, pendekatan greedy dapat

memberikan komputasi yang sangat cepat dan mendekati hasil

optimum global [2, 3].

A. Memoization

Salah satu penerapan pemrograman dinamis adalah dengan

memoization, yaitu mencoba mencari hasil yang diharapkan dari

‘memo’ atau data container yang tersedia. Jika tidak tersedia,

baru dilakukan komputasi, dan hasilnya dicatat dalam ‘memo’

tsb. supaya dapat digunakan untuk proses selanjutnya jika

diperlukan. Keuntungan metode ini adalah pencatatan hanya

dilakukan jika diperlukan (on demand) [1].

B. Tabulation

Pendekatan lainnya adalah dengan tabulasi, yaitu membuat

tabel dari sub-permaslahan paling sederhana, sampai yang

paling kompleks. Kemudian jika diperlukan, cukup mengakses

hasil yang sudah dikomputasi terlebih dahulu. Dalam

pendekatan ini, semua kemungkinan akan dicoba dan dicatat

hasil komputasinya [1].

III. GREEDY APPROACH

Paradigma pendekatan greedy adalah suatu paradigma

algoritma dimana dengan memanfaatkan heuristic, mencari opsi

/ pilihan optimum lokal, dengan harapan akan menghasilkan

optimum global pada akhirnya [4].

Secara umum, pendekatan greedy tidak akan menghasilkan

solusi optimum global, namun kenyataanya pada kebanyakan

permasalahan, dapat menghasilkan solusi yang menghampiri

optimum global, (dengan mengambil optimum lokal pada setiap

tahapnya) dan yang terpenting: dengan kompleksitas waktu

yang sangat minimum.

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

Pendekatan greedy umumnya menggunakan heuristic

(aturan yang dianggap benar dan dapat menghasilkan

aproksimasi solusi optimum) dan preprocessing data supaya

meminimalisasi kompleksitas saat mencari solusi nantinya.

IV. KNAPSACK PROBLEMS

The knapsack problem adalah suatu permasalahan optimasi

menggunakan kombinatorial: terdapat sekumpulan benda yang

memiliki berat dan nilai, tentukan benda mana saja yang harus

dimasukan dalam himpunan supaya berat tidak melebihi batas,

namun menghasilkan profit paling tinggi [5].

Secara umum, jenis permasalahan yang paling umum adalah

0-1 knapsack problem, dimana banyak benda untuk setiap

jenisya hanya berkisar 0 (tidak dimasukkan) atau 1

(dimasukkan) [6].

Dalam notasi matematis:

∑ 𝑣𝑖𝑥𝑖

𝑛

𝑖=1

dengan mempertimbangkan:

∑ 𝑤𝑖𝑥𝑖

𝑛

𝑖=1

≤ 𝑊, 𝑥𝑖 ∈ {0, 1}.

n = jumlah jenis benda,

w = berat benda

x = banyak benda

v = nilai benda

W = berat kapasitas maksimum

Dalam penyelesaian permasalahan knapsack, walaupun

permasalahan menentukan putusannya (decision problem)

tergolong NP-complete, persoalan optimasi knapsack sendiri

tergolong NP-hard, sehingga solusi optimum tidak dapat

ditentukan / belum ada algoritma yang dapat menentukan solusi

dalam kompleksitas polinomial. Namun kompleksitas dapat

diturunkan menjadi pseudo-polinomial menggunakan

pendekatan pemrograman dinamis (dynamic programming) [7].

A. Pemanfaatan Dynamic Programming

Pada persoaalan ini, didefinisikan tahap – k adalah proses

memasukkan barang k ke dalam himpunan solusi, sedangkan

status y adalah kapasitas muat yang tersisa setelah memasukkan

barang pada tahap sebelumnya.

Relasi rekurens yang didefinisikan adalah:

𝑓0(𝑦) = 0, 𝑦 = 0, 1, … , 𝑀 (basis) (3)

𝑓𝑘(𝑦) = −∞, 𝑦 < 0 (basis) (4)

𝑓𝑘(𝑦) = max {𝑓𝑘−1, 𝑝𝑘 + 𝑓𝑘−1(𝑦 − 𝑤𝑘)} (rekurens) (5)

𝑓𝑘(𝑦) adalah keuntungan optimum dari persoalan pada tahap

k untuk kapasitas sebesar y. 𝑓0(𝑦) = 0 adalah basis knapsack

kosong, sedangkan 𝑓𝑘(𝑦) = −∞ adalah basis knapsack jika

kapasitas lebih kecil daripada beban benda [8]. Berikut pseudo-

codenya:

1. // Values (stored in array v) 2. // Weights (stored in array w) 3. // Number of distinct items (n) 4. // Knapsack capacity (W) 5. 6. for j from 0 to W do: 7. m[0, j] := 0 8. 9. for i from 1 to n do: 10. for j from 0 to W do: 11. if w[i] > j then: 12. m[i, j] := m[i-1, j] 13. else: 14. m[i, j] := max(m[i-1, j], m[i-

1, j-w[i]] + v[i])

B. Multi-objective Knapsack

Dalam perkembangan varian dari knapsack problems,

terdapat suatu varian multi-objective yaitu dimana profit yang

diinginkan mungkin memiliki dimensi lebih dari satu. (contoh:

memaksimalkan profit dan maksimal jumlah barang yang

dibawa) [9].

C. Multi-dimensional Knapsack

Dalam perkembangan varian dari knapsack problems,

terdapat suatu vaian multi-dimensional-knapsack yaitu dimana

‘berat’ yang menjadi kapasitas berdimensi lebih dari satu.

(contoh: berat tidak melebihi x , dan jumlah benda a tidak

melebihi y) [10].

V. PERSIAPAN SIMULASI

Setelah membahas beberapa dasar teori dalam simulasi

penyelesaian masalah, perlu didefinisikan juga domain

permasalahan dan ruang lingkup permasalahan sebelum

mencoba menyelesaikannya. Juga tidak lupa membuat data

sample untuk digunakan pada proses pemecahan masalah.

A. Domain permasalahan

Untuk simulasi permasalahan memilih penyewa (tenant)

dalam mal, diasumsikan setiap tenant memiliki data jenis slot

yang dibutuhkan, profit (uang) yang akan diterima pengembang

(asumsi konstant untuk sepanjang kontrak yang didefinisikan),

estimasi kontribusi peningkatan rating mal (asumsikan hasil

survey popularitas tenant yang dilakukan pengembang). Data

yang diperlukan disederhanakan karena hanya untuk keperluan

simulasi.

Untuk merepresentasikan ‘weight’ dalam knapsack,

digunakan slot yang merepresentasikan ‘ruangan’ yang dapat

disewakan, namun supaya menyerupai kasus pada kenyataanya,

maka slot dibagi menjadi beberapa tipe, dan masing-masing

memiliki jumlah yang terbatas.

Untuk knapsack nya sendiri, berupa abstraksi dari slot yang

terdapat pada setiap lantai mal. Hal ini dilakukan untuk

mensimulasikan peletakan dan penyusunan tenant seperti pada

kenyataanya. Sehingga permasalahan dispesifikasi menjadi

multi-bag knapsack problem.

(1) memaksimalkan

(2)

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

B. Pembatasan Masalah

Dalam simulasi, diasumsikan penentuan jumlah masing-

masing jenis slot ditentukan oleh pengembang setelah melewati

tahap perancangan gedung dan bukan menjadi domain simulasi.

Profit yang dimaksud juga adalah pemasukan konstan yang

diberikan oleh tenant, dan diasumsikan dihitung per tahun,

sehingga profit maksimum yang dioptimasi adalah profit per

tahunnya.

Walaupun pada dasarnya persoalan adalah multi-objective

knapsack, namun diasumsikan semua profit yang diinginkan

dapat direduksi menjadi satu dimensi (satu konstanta) sesuai

proporsi dan kepentingan masing-masing nilai dengan

pendekatan greedy yaitu menggunakan persamaan linier yang

memuat hubungan semua atribut yang ingin dimaksimalkan.

Segala faktor eksternal lainnya disederhanakan dan tidak

masuk domain optimasi dalam persoalan knapsack ini.

C. Data sampel

Sebelum memulai simulasi, diperlukan data yang telah

disebutkan diatas, yaitu data tenant dan data kapasitas mal.

Penciptaan data dilakukan dengan random oleh library Numpy.

Data dibuat dengan cara menentukan untuk masing-masing

kategori tenant, (slot a / b / c / d / e), mean dan standard

deviation dari pesebaran distribusi profit dan ratingnya. Setelah

itu, menggukanan fungsi distribusi normal dari Numpy untuk

menciptakan data pseudo-randomnya.

Berikut contoh hasil pembuatan data tenant dari masing

masing kategori menggunakan kode pada appendix 3 sampai 7:

Tabel 1. Contoh Data Tenant Kategori ‘a’

Id

tenant Profit kontrak (jt) Rating

Jenis slot

(a, b, c, d, e)

1 148 10 (1, 0, 0, 0, 0)

2 147 10 (1, 0, 0, 0, 0)

3 176 6.92 (1, 0, 0, 0, 0)

… … … …

30 167 10 (1, 0, 0, 0, 0)

Tabel 2. Contoh Data Tenant Kategori ‘b’

Id

tenant Profit kontrak (jt) Rating

Jenis slot

(a, b, c, d, e)

31 74 7.5 (0, 1, 0, 0, 0)

32 73 9.12 (0, 1, 0, 0, 0)

33 90 8.84 (0, 1, 0, 0, 0)

… … … …

80 53 6.61 (0, 1, 0, 0, 0)

Tabel 3. Contoh Data Tenant Kategori ‘c’

Id

tenant Profit kontrak (jt) Rating

Jenis slot

(a, b, c, d, e)

81 49 9.85 (0, 0, 1, 0, 0)

82 48 4.99 (0, 0, 1, 0, 0)

83 60 5.46 (0, 0, 1, 0, 0)

… … … …

280 54 6.96 (0, 0, 1, 0, 0)

Tabel 4. Contoh Data Tenant Kategori ‘d’

Id

tenant Profit kontrak (jt) Rating

Jenis slot

(a, b, c, d, e)

281 24 2.27 (0, 0, 0, 1, 0)

282 24 5.03 (0, 0, 0, 1, 0)

283 30 6.55 (0, 0, 0, 1, 0)

… … … …

430 24 4.03 (0, 0, 0, 1, 0)

Tabel 5. Contoh Data Tenant Kategori ‘e’

Id

tenant Profit kontrak (jt) Rating

Jenis slot

(a, b, c, d, e)

431 4 4.77 (0, 0, 0, 0, 1)

432 4 0 (0, 0, 0, 0, 1)

433 6 3.76 (0, 0, 0, 0, 1)

… … … …

680 7 3.51 (0, 0, 0, 0, 1)

Jika dilihat sekilas, setiap tenant hanya memiliki bobot

‘weight’ 1 untuk jenis kategori tertentu (misal (0, 1, 0, 0, 0) atau

(0, 0, 0, 1, 0,), untuk kasus sederhana seperti itu, pemilihan

tenant dapat dilakukan hanya dengan sorting profit dan diambil

nilai terbesar pertama sampai nilai kapasitas tertentu setiap

lantai saja.

Maka untuk menambah kompleksitas dan mencoba

menyerupai permasalahan pada kenyataan dimana suatu tenant

dapat menyewa beberapa tipe / beberapa slot sekaligus, maka

akan dilakukan penggabungan data. Penggabungan dilakukan

secara random (menggunakan kode appendix 9 dan 10).

Alasan penggabungan dilakukan belakangan adalah untuk

menjaga keselarasan data profit kontrak, rating, jumlah tenant

per kategori, dengan jenis slot yang diperlukan. Misalnya:

mengindari adanya tenant yang profit kontraknya kecil (tipe e)

tapi menyewa slot tipe a. (data lebih realistis).

Tabel 6. Contoh Data Tenant Kombinasi

Id

tenant Profit kontrak (jt) Rating

Jenis slot

(a, b, c, d, e)

11 141 9.45 (1, 0, 2, 0, 0)

27 282 8.8 (1, 0, 3, 0, 0)

54 128 6.84 (0, 1, 2, 0, 0)

… … … …

672 17 7.2 (0, 0, 0, 0, 2)

Selanjutnya adalah data slot yang dimiliki masing-masing

lantai dalam mal tsb. Pembuatan data juga dilakukan dengan

library Numpy untuk menciptakan data yang random.

Berikut hasil pembuatan data slot mal yang akan digunakan

pada tahap berikutnya (menggunakan kode appendix 11):

Tabel 7. Jumlah Masing-masing Slot

Lantai ‘a’ ‘b’ ‘c’ ‘d’ ‘e’

1 2 6 26 14 18

2 2 8 36 22 25

3 1 6 33 25 22

4 2 6 30 10 24

5 2 16 19 15 21

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

VI. PEMECAHAN MASALAH

Setelah mendefinisikan berbagai teori dan data yang akan

digunakan dalam simulasi, berikutnya adalah pelaksanaan

simulasi dan analisis permasalahan itu sendiri.

A. Perkiraan Kompleksitas

Sebelum memulai mencoba membuat kode penyelesaianya,

jika sekilas kita menghitung kompleksitasnya:

𝑂(#𝑡𝑒𝑛𝑎𝑛𝑡 × 𝑆𝑎1 × 𝑆𝑎2 × … × 𝑆𝑒5)

(Nb: Sa1 menandakan jumlah slot tipe a di lantai 1, Se5 adalah

jumlah slot tipe e di lantai 5)

Sekedar gambaran, jika menggunakan data pada tabel 7, dan

sekitar 400 tenant, jumlah komputasi maksimumnya (worst

case) adalah 2.14 * 10^29. Sebagai pembanding, jika dalam satu

detik dapat melakukan 10^8 komputasi, diperlukan 6.8 * 10^13

tahun untuk menyelesaikannya. Namun untuk kepentingan

simulasi, komputasi akan tetap dilakukan walaupun jumlah data

dikurangi.

B. Percobaan Dynamic Programming

Saat melakukan percobaan, (dengan kode appendix 17),

dengan menggunakan sample hanya 13 tenant dan kondisi ‘bag’

seperti pada tabel 7, didapatkan hasil nilai maksimum 2280

(profit multi dimensi direduksi menjadi satu dimensi dengan

kode appendix 16 sesuai keterangan dalam pembatasan

masalah).

Dari tabel yang digunakan dalam dynamic programming,

dapat disimpulkan tenant mana saja yang diambil, dan dengan

menggunakan kode appendix 18, hasil yang didapat adalah

tenant berikut :

(no, profit, rating, a b c d e)

[1. , 148., 10., 1., 0., 0., 0., 0.],

[6. , 143., 10., 1., 0., 1., 0., 0.],

[7. , 166., 8.96, 1., 0., 1., 0., 0.],

[8. , 144., 10., 1., 0., 0., 0., 0.],

[9. , 183., 9.37, 1., 0., 1., 0., 0.],

[10. , 149., 9.34, 1., 0., 0., 0., 0.],

[11. , 134., 9.45, 1., 0., 0., 0., 0.],

[12. , 184., 9.33, 1., 0., 0., 0., 0.],

[13. , 190., 8.37, 1., 0., 0., 0., 0.]

Artinya: tenant dengan nomor 1, 6, 7, 8, 9, 10, 11, 12, 13 akan

mendapat jatah jika hanya ada 13 tenant.

Yang perlu diperhatikan adalah bahwa jumlah slot a yang

tersedia ada 9, dan jumlah slot a yang dipakai tenant yang

terpilih juga 9, ini artinya tenant yang dipilih sudah

memaksimalkan profit yang akan didapat pengembang. Hasil ini

menunjukkan bahwa problema ini dapat diselesaikan dengan

optimum menggunakan pendekatan dynamic programming.

Walaupun hanya 13 tenant, komputasi yang dilakukan

mencapai 1238798 atau 1.2 juta komputasi. Tentu jumlah ini

tergolong besar untuk 13 jenis ‘barang’ dalam knapsack

problem. Melalui contoh diatas, penulis berusaha mencari

jumlah sample yang cukup sesuai untuk menunjukkan bahwa

problema dapat diselesaikan walaupun di satu pihak, pendekatan

dynamic programming ini tidak scalable.

C. Grafik Jumlah Komputasi

Jika percobaan dilakukan kembali, namun kali ini mencatat

hubungan jumlah tenant dan jumlah komputasi yang dilakukan

mulai dari hanya ada 1 tenant sampai terdapat 13 tenant (kode

appendix 20), didapatkan hasil:

Output: [(13, 1238798), (12, 779080), (11, 447802), (10,

247517), (9, 113852), (8, 52541), …, (3, 43), (2, 7), (1, 1)]

Sebagai gambaran data tsb. dalam bentuk grafik:

Gambar 1. Grafik Jumlah Komputasi(y) dan Jumlah

Tenant(x)

Sumber(kode appendix 21)

Walaupun sekilas tampak seperti jumlah bertumbuh secara

eksponensial, namun jika dibuat grafik hubungan jumlah tenant

dengan logaritma dari jumlah komputasi, didapatkan grafik

seperti berikut:

Gambar 2. Grafik Log Jumlah Komputasi(y) dan Jumlah

Tenant(x)

Sumber(kode appendix 22)

Dari grafik ini disimpulkan bahwa kompleksitas algoritma,

masih dikatakan polinomial (pseudo-polinomial), walaupun

orde polinomnya sangat besar. Dengan demikian, teori bahwa

problema dapat diselesaikan dalam kompleksitas pseudo-

polinomial dapat dibuktikan.

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

Kembali ke permasalahan, terlihat jelas bahwa pendekatan

dynamic programming ini tidak terlalu dapat diandalkan, karena

pada kenyataanya, datanya tidak sesederhana dan sesedikit ini,

faktor pertimbangan akan jauh lebih rumit dan juga ‘weight’

yang digunakan akan berdimensi lebih banyak lagi.

Maka dari itu, dibutuhkan pendekatan lain yang lebih scalable

terutama dalam hal waktu komputasi. Salah satu pendekatan

yang sesuai adalah: Greedy.

VII. PEMECAHAN MASALAH II

Salah satu kelebihan pendekatan greedy adalah dengan

melakukan preprocessing data dan menerapkan berbagai

heuristic, sehingga waktu komputasi dapat ditekan. Dalam

kasus ini, juga diperlukan beberapa tahap preprocessing data.

A. Sorting Tenant

Pertama-tama perlu dilakukan sorting tenant sesuai profit

yang diberikan, namun dalam data sample yang digunakan, akan

terjadi bias jika dilakukan terhadap profit, karena tenant tipe a

cenderung memiliki profit tertinggi. Sehingga dilakukan sorting

terhadap efisiensi tenant yang didefinisikan sebagai: profit / cost

slot yang diperlukan.

Untuk cost yang didefinisikan, ditentukan secara tentative:

misalkan slot tipe a diberi nilai 150 sedangkan tipe e hanya

bernilai 5.

Pada kasus ini, cost slot disamakan dengan rata-rata profit

tenant per kategori (a-e) (mengikuti mean yang digunakan saat

penciptaan data tenant). Hal ini didasarkan pada intuitif bahwa

tenant yang menghasilkan profit lebih banyak dari tenant sejenis

(kategori sama & memakai jumlah slot yang sama), akan lebih

diutamakan.

Berikut tabel 8 dan tabel 9 hasil kode appendix 23 dan 24:

Tabel 8. Contoh Data Tenant + efisiensi

Id

tenant

Profit

kontrak

(jt)

Rating

Jenis slot

(a, b, c, d, e)

Eff

1 148 10 (1, 0, 0, 0, 0) 1.667

2 147 10 (1, 0, 0, 0, 0) 1.435

3 176 6.92 (1, 0, 0, 0, 0) 1.130

… … … …

30 167 10 (1, 0, 0, 0, 0) 1.793

Tabel 9. Contoh Data Tenant Terurut Eff

Id

tenant

Profit

kontrak

(jt)

Rating

Jenis slot

(a, b, c, d, e)

Eff

74 102 10 (0, 1, 0, 0, 0) 2.720

58 87 10 (0, 1, 0, 0, 0) 2.520

95 56 8.59 (0, 0, 1, 0, 0) 1.88

… … … …

283 30 6.55 (0, 0, 1, 0, 0) 0.78

B. Uji Coba Greedy

Berbeda dengan pendekatan dynamic programming dimana

semua kemungkinan yang diperlukan akan dicoba, karena dalam

pendekatan greedy sudah dilakukan preprocessing data dengan

diurutkan berdasarkan ‘prioritas’, maka saat memilih, cukup

memeriksa apakah suatu tenant dapat masuk di lantai ke – n, jika

ya, masukkan dalam himpunan solusi ke – n. Jika tidak dapat

dimasukkan ke lantai manapun, masukkan kedalam himpunan

yang tidak dipilih.

Untuk mencari solusi dengan pendekatan greedy, digunakan

kode appendix 25: didapatkan hasil profit sebesar 15713 dan

kali ini, semua data tenant digunakan. Jumlah komputasi yang

diperlukan tentu saja sangat minimum, yaitu: (maksimal /

worstcase):

𝑂(#𝑡𝑒𝑛𝑎𝑛𝑡 × #𝑙𝑎𝑛𝑡𝑎𝑖)

Dalam kasus ini, hanya 544 * 5 = 2720, sangat jauh lebih

sedikit dibandingkan pendekatan dynamic programming.

Hasil dari pendekatan greedy pun dapat menunjukkan tenant

mana saja yang dimasukkan dalam lantai yang mana (kode

appendix 27):

Output:

Lantai 1 = [645, 601, 501, 583, 619, 647, 74, 81, 584, 58,

453, 567, 57, 40, 331, 28, 378, 267, …, 208, 202, 115, 340,

214, 233, 277, 365, 293, 427, 381, 324]

Lantai 2 = [38, 78, 65, 67, 68, 42, 49, 589, 33, 526, 631, 15,

1, 603, 577, 662, …,341, 361, 414]

Lantai 3 = [12, 75, 50, 69, 66, 43, 39, 517, 490, 678, 614,

671, ..., 420, 334]

Lantai 4 = [8, 9, 47, 46, 41, 34, 45, 71, 654, 652, 641, 482,

472, 439, 582, 445, 502, 458…10, 392, 320, 315, 364, 298]

Lantai 5 = [5, 23, 60, 36, 48, …, 291, 319, 200, 199, 395,

183, 376, 235, 82, 196, 160, 327, 269, 144, 148]

* Hasil tidak ditampilkan semua

Hasil diatas, jika dirangkum menurut jumlah tenant per

lantai, didapatkan hasil [60, 75, 70, 60, 49] dimana artinya

314/544 tenant mendapatkan tempat dalam gedung. Terlihat

kurang baik karena hanya 57% yang dimasukkan, namun jika

kita meninjau lagi sisa slot dalam gedung yang tidak terpakai:

Output:

[[ 1., 0., 0., 0., 0., 0.],

[ 2., 0., 0., 0., 0., 0.],

[ 3., 0., 0., 0., 0., 0.],

[ 4., 0., 0., 0., 0., 0.],

[ 5., 0., 0., 0., 0., 0.]]

Ternyata semua slot habis dipakai! Apakah hal ini

membuktikan bahwa pendekatan greedy menjamin solusi

efektif dan optimum untuk semua kasus?

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

Jika kita ingat kembali, pada bagian pembuatan data, data

slot yang dibutuhkan tenant pada umumnya berupa data singular

atau hanya memiliki bobot untuk satu jenis slot saja misal (0, 0,

0, 0, 1) atau (0, 0, 1, 0, 0). Sehingga, sisa sisa slot dapat dengan

mudah dipenuhi oleh tenant-tenant dengan kebutuhan slot

seperti ini.

Dengan kata lain, pendekatan greedy akan optimal jika

terdapat pecahan terkecil yang dapat memenuhi slot sisa sekecil

apapun. Dengan bertambahnya data, dan ketersediaan tenant

(‘object’ dalam kasus knapsack), akan lebih mudah bagi

pendekatan greedy untuk mendapatkan hasil mendekati

optimum global.

VIII. KESIMPULAN

Berdasarkan percobaan untuk memasukan tenant dengan

bobot lima dimensi, dan profit berdimensi dua: didapatkan

pendekatan dynamic programming dapat dilakukan dan

menjamin kompleksitas Pseudo-polinomial.

Walaupun dikatakan polinomial, namun polinomial tsb. dapat

berkembang dengan orde besar terutama jika dimensi ‘weight’

barang (dalam kasus uji: slot) dan jumlah ‘bag’ (dalam kasus

uji: lantai) bertambah. Terbukti dari percobaan dan grafik yang

menunjukkan pertumbuhan jumlah komputasi.

Pendekataan lain yang dapat dipakai untuk kasus ini adalah

greedy dengan bantuan heuristic. Dalam percobaan ini,

pendekatan greedy dapat bekerja mendekati optimum, dan

dibuktikan dengan semua slot terpakai. Hasil yang mendekati

optimum dapat dicapai apabila terdapat ‘object’ yang dapat

memiliki ‘weight’ dalam satuan terkecil untuk setiap jenis

‘weight’ yang dibatasi oleh pembatas muatan (capacity).

Walaupun pendekatan greedy memerlukan preprocessing,

namun kompleksitasnya tetap jauh lebih kecil dibandingkan

dynamic programming.

Pendekatan greedy bisa dikatakan jauh lebih cocok untuk

diterapkan dalam kasus uji seperti ini karena paling tidak

menghasilkan solusi mendekati optimum, dibandingkan

dynamic programming yang tidak menghasilkan solusi karena

keterbatasan waktu komputasi jika dihadapkan dengan jumlah

‘object’ dan ‘bag’ yang besar.

IX. APPENDIX

Appendix diberikan secara terpisah karena keterbatasan

halaman.

X. ACKNOWLEDGMENT

Terimakasih kepada Tony (IF ITB 2016) yang sudah turut

membantu dan mendukung kelancaran pembuatan makalah ini,

terutama dalam hal konsultasi algoritma dan penerapan yang

efektif.

REFERENCES

[1] Https://www.geeksforgeeks.org/dynamic-programming-set-1/

(diakses 6 Mei 2018)

[2] Cormen, T. H.; Leiserson, C. E.; Rivest, R. L.; Stein, C. (2001),

Introduction to Algorithms (2nd ed.), MIT Press & McGraw–Hill,

ISBN 0-262-03293-7. pp. 344.

[3] W.-K. Chen, Linear Networks and Systems (Book style). Belmont,

CA: Wadsworth, 1993, pp. 123–135.

[4] Black, Paul E. (2 February 2005). "greedy algorithm". Dictionary

of Algorithms and Data Structures. U.S. National Institute of

Standards and Technology (NIST)

[5] Mathews, G. B. (25 June 1897). "On the partition of numbers"

(PDF). Proceedings of the London Mathematical Society. 28: 486–

490. doi:10.1112/plms/s1-28.1.486l

[6] Kellerer, Pferschy, and Pisinger 2004, p. 472

[7] Poirriez, Vincent; Yanev, Nicola; Andonov, Rumen (2009). "A

hybrid algorithm for the unbounded knapsack problem". Discrete

Optimization. 6 (1): 110–124.

[8] http://informatika.stei.itb.ac.id/~rinaldi.munir/Stmik/2017-

2018/Program-Dinamis-(2018).pdf (diakses 7 Mei 2018)

[9] https://arxiv.org/ftp/arxiv/papers/1007/1007.4063.pdf (diakses 7

Mei 2018)

[10] Gens, G. V. and Levner, E. V. (1979). "Complexity and

Approximation Algorithms for Combinatorial Problems: A

Survey". Central Economic and Mathematical Institute, Academy

of Sciences of the USSR, Moscow.

PERNYATAAN

Dengan ini saya menyatakan bahwa makalah yang saya tulis

ini adalah tulisan saya sendiri, bukan saduran, atau terjemahan

dari makalah orang lain, dan bukan plagiasi.

Bandung, 3 Desember 2017

Ttd (scan atau foto ttd)

Jessin 13516112

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

IX. APPENDIX

Kode 1: Import

1. %matplotlib inline 2. import numpy as np 3. import warnings 4. 5. warnings.filterwarnings(action='ignore')

Kode 2: Fungsi formatting atribut popularitas

1. def format_popularity(tenant_popularity): 2. """ Format popularity to range between 0 - 10, and with 2 decimal value """ 3. 4. tenant_popularity[tenant_popularity < 0] = 0 5. tenant_popularity[tenant_popularity > 10] = 10 6. tenant_popularity = np.around(tenant_popularity, 2) 7. 8. return tenant_popularity

Kode 3: Generate tenant kategori ‘a’

1. np.random.seed(seed=21) 2. 3. tenant_id = np.arange(1, 31) 4. tenant_profit = np.random.normal(150, 25, 30) // 1 5. tenant_popularity = np.random.normal(9, 1.5, 30) 6. tenant_popularity = format_popularity(tenant_popularity) 7. 8. zeros = np.zeros((30, 1)) 9. ones = np.ones((30,1)) 10. tenant_slot = np.hstack((ones,zeros,zeros,zeros,zeros)) 11. 12. # merge the data 13. tenant_data_a = np.vstack((tenant_id, tenant_profit, tenant_popularity)).T 14. tenant_data_a = np.hstack((tenant_data_a, tenant_slot))

Kode 4: Generate tenant kategori ‘b’

1. np.random.seed(seed=21) 2. 3. tenant_id = np.arange(31, 81) 4. tenant_profit = np.random.normal(75, 15, 50) // 1 5. tenant_popularity = np.random.normal(8, 1.5, 50) 6. tenant_popularity = format_popularity(tenant_popularity) 7. 8. zeros = np.zeros((50, 1)) 9. ones = np.ones((50,1)) 10. tenant_slot = np.hstack((zeros,ones,zeros,zeros,zeros)) 11. 12. # merge the data 13. tenant_data_b = np.vstack((tenant_id, tenant_profit, tenant_popularity)).T 14. tenant_data_b = np.hstack((tenant_data_b, tenant_slot))

Kode 5: Generate tenant kategori ‘c’

1. np.random.seed(seed=21) 2. 3. tenant_id = np.arange(81, 281) 4. tenant_profit = np.random.normal(50, 10, 200) // 1 5. tenant_popularity = np.random.normal(6, 1.5, 200)

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

6. tenant_popularity = format_popularity(tenant_popularity) 7. 8. zeros = np.zeros((200, 1)) 9. ones = np.ones((200,1)) 10. tenant_slot = np.hstack((zeros,zeros,ones,zeros,zeros)) 11. 12. # merge the data 13. tenant_data_c = np.vstack((tenant_id, tenant_profit, tenant_popularity)).T 14. tenant_data_c = np.hstack((tenant_data_c, tenant_slot))

Kode 6: Generate tenant kategori ‘d’

1. np.random.seed(seed=21) 2. 3. tenant_id = np.arange(281, 431) 4. tenant_profit = np.random.normal(25, 5, 150) // 1 5. tenant_popularity = np.random.normal(4, 1.5, 150) 6. tenant_popularity = format_popularity(tenant_popularity) 7. 8. zeros = np.zeros((150, 1)) 9. ones = np.ones((150,1)) 10. tenant_slot = np.hstack((zeros,zeros,ones,zeros,zeros)) 11. 12. # merge the data 13. tenant_data_d = np.vstack((tenant_id, tenant_profit, tenant_popularity)).T 14. tenant_data_d = np.hstack((tenant_data_d, tenant_slot))

Kode 7: Generate tenant kategori ‘e’

1. np.random.seed(seed=21) 2. 3. tenant_id = np.arange(431, 681) 4. tenant_profit = np.random.normal(5, 1.5, 250) // 1 5. tenant_popularity = np.random.normal(2, 2.5, 250) 6. tenant_popularity = format_popularity(tenant_popularity) 7. 8. zeros = np.zeros((250, 1)) 9. ones = np.ones((250,1)) 10. tenant_slot = np.hstack((zeros,zeros,ones,zeros,zeros)) 11. 12. # merge the data 13. tenant_data_e = np.vstack((tenant_id, tenant_profit, tenant_popularity)).T 14. tenant_data_e = np.hstack((tenant_data_e, tenant_slot))

Kode 8: Gabungkan kelima jenis tenant

1. tenant = np.vstack((tenant_data_a , tenant_data_b, tenant_data_c , tenant_data_d , tenant_data_e)) 2. tenant.shape

Kode 9: Fungsi penggabungan tenant

1. def combine(tenant_data, t1, t2): 2. 3. try: 4. tenant_1 = tenant_data[t1] 5. tenant_2 = tenant_data[t2] 6. 7. # sum profit 8. tenant_1[1] += tenant_2[1] 9. 10. # avg popularity 11. tenant_1[2] = max((tenant_1[2] , tenant_2[2])) 12. 13.

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

14. # sum the necesary slot 15. for i in range(3,8): 16. tenant_1[i] += tenant_2[i] 17. 18. # delete second entry 19. tenant_data = np.delete(tenant_data, t2, axis=0) 20. 21. return tenant_data 22. 23. except: 24. return tenant_data

Kode 10: Pemanggilan fungsi penggabung

1. tenant_count_init = tenant_count = tenant.shape[0] 2. 3. # reduce tenant to below 80% by merging some tenant 4. while(tenant_count > 0.80 * tenant_count_init): 5. 6. tenant_partner = np.random.randint(0, tenant_count * 4, tenant_count) # each tenant only has 2

5% change to be merged 7. 8. for i in range(0, tenant_count): 9. if i < tenant_partner[i]: 10. tenant = combine(tenant, i, tenant_partner[i]) 11. 12. tenant_count = tenant.shape[0] 13. 14. tenant.shape

Kode 11: Generate slot dalam mal

1. np.random.seed(seed=23) 2. 3. building_floor = np.arange(1,6) 4. slot_type_a = np.random.normal(3, 1, 5) // 1 5. slot_type_b = np.random.normal(10, 3, 5) // 1 6. slot_type_c = np.random.normal(30, 10, 5) // 1 7. slot_type_d = np.random.normal(20, 5, 5) // 1 8. slot_type_e = np.random.normal(20, 5, 5) // 1 9. 10. # merge the data 11. building = np.vstack((building_floor, slot_type_a, slot_type_b, slot_type_c, slot_type_d, slot_typ

e_e)).T

Kode 12: Json object dari slot mal

1. json_building = {} 2. for floor in building: 3. 4. temp = {} 5. for i in range(1, len(floor)): 6. temp[chr(i + 96)] = floor[i] 7. 8. json_building[floor[0]] = temp

Kode 13: merubah building menjadi tuples untuk JSON indexing

1. def capacity_list(building): 2. 3. index = [] 4. for floor in building: 5. for i in range(1, len(floor)): 6. index.append(floor[i])

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

7. 8. return tuple(index)

Kode 14: mengecek ketersediaan slot

1. def enough_slot(tenant, floor_slot): 2. 3. for i in range(1, len(floor_slot)): 4. if floor_slot[i] < tenant[2 + i]: 5. return False 6. return True

Kode 15: mengurangi slot lantai

1. def reduce_slot(tenant, building, floor): 2. 3. temp = copy.deepcopy(building) 4. for i in range(1, len(temp[floor])): 5. temp[floor][i] -= tenant[2 + i] 6. 7. return temp

Kode 16: estimasi profit (reduksi dimensi)

1. def estimated_value(tenant): 2. 3. return int(tenant[1] + (2**tenant[2])/10)

Kode 17: pendekatan dynamic programming

1. def solve(tenant_number, building): 2. global dpdict 3. global table_c, compute_c 4. 5. # if tenant number out of bound 6. try: 7. tenant[tenant_number] is not None 8. except: 9. return 0 10. 11. if (tenant[tenant_number] is not None): 12. 13. item = tenant[tenant_number] 14. capacity_tuple = capacity_list(building) 15. 16. try: 17. # check if json dict available 18. if dpdict[item[0]][capacity_tuple] is not None: 19. 20. table_c += 1 21. return dpdict[item[0]][capacity_tuple] 22. 23. except Exception as e : 24. 25. # set dict value 26. if item[0] not in dpdict.keys(): 27. dpdict[item[0]] = {} 28. dpdict[item[0]][capacity_tuple] = solve(tenant_number + 1, building) 29. 30. # check if it's available for each floor 31. for i in range(0, 5): 32. 33. if enough_slot(item, building[i]): 34.

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

35. # value from DP dict 36. old_value = dpdict[item[0]][capacity_tuple] 37. 38. # computed new value 39. new_building = reduce_slot(item, building, i) 40. new_value = solve(tenant_number + 1, new_building) + estimated_value(item) 41. 42. # Re write dict 43. dpdict[item[0]][capacity_tuple] = max(old_value, new_value) 44. 45. compute_c += 1 46. return dpdict[item[0]][capacity_tuple] 47. 48. 49. # Run the function 50. tenant = tenant[:13] 51. dpdict = {} 52. table_c = compute_c = 0 53. 54. solve(0, building)

Kode 18: menampilkan hasil dynamic programming

1. def list_tenant(building): 2. 3. ans = [] 4. w = capacity_list(building) 5. for i in range (len(tenant) - 1): 6. 7. curr_tenant = tenant[i] 8. 9. # tenant not included 10. if dpdict[curr_tenant[0]][w] == dpdict[tenant[i + 1][0]][w]: 11. continue 12. 13. 14. for j in range(0, len(building)): 15. wtemp = capacity_list(reduce_slot(curr_tenant, building, j)) 16. try: 17. if dpdict[curr_tenant[0]][w] == dpdict[tenant[i + 1][0]][wtemp] + estimated_value(

curr_tenant) : 18. ans.append(curr_tenant) 19. w = wtemp 20. break 21. except: 22. pass 23. 24. i = len(tenant) - 1 25. if dpdict[tenant[i][0]][w] > 0: 26. ans.append(tenant[i]) 27. 28. return ans 29. 30. # Run the function 31. list_tenant(building)

Kode 19: persiapan data untuk di plot

1. res = [] 2. for i in range(-13, 0): 3. 4. tenant = tenant[:-i] 5. dpdict = {} 6. table_c = compute_c = 0 7.

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

8. solve(0, building) 9. 10. res.append((-i, table_c + compute_c)) 11. print(res)

Kode 20: plot grafik

1. import matplotlib.pyplot as plt 2. 3. plt.plot(*zip(*res)) 4. plt.show()

Kode 21: plot grafik logaritma

1. from math import log 2. 3. reslog = [(elem1, log(elem2)) for elem1, elem2 in res] 4. plt.plot(*zip(*reslog)) 5. plt.show()

Kode 22: kalkulasi efisiensi

1. def tenant_eff(tenant): 2. 3. mean = 0 4. mean += tenant[3] * 150 5. mean += tenant[4] * 75 6. mean += tenant[5] * 50 7. mean += tenant[6] * 25 8. mean += tenant[7] * 5 9. 10. return estimated_value(tenant) / mean

Kode 23: kalkulasi efisiensi

1. eff = [[tenant_eff(x)] for x in tenant] 2. tenant_greed = np.hstack((tenant, eff))

Kode 24: Sort greedy

1. tenant_greed = tenant_greed[tenant_greed[:,8].argsort()][::-1]

Kode 25: Greedy algorithm

1. def solve_g(tenant, building): 2. 3. global compute_c 4. 5. result = [[] for _ in range(0,5)] 6. not_used = [] 7. profit = 0 8. 9. count = 0 10. for each_tenant in tenant: 11. 12. flag = True 13. for i in range(0, 5): 14. print("checking", i) 15. if enough_slot(each_tenant, building[i]): 16. 17. # computed new value 18. building = reduce_slot(each_tenant, building, i)

Makalah IF2120 Matematika Diskrit – Sem. I Tahun 2017/2018

19. profit += estimated_value(each_tenant) 20. 21. # insert tenant into building 22. result[i].append(each_tenant) 23. flag = False 24. 25. print("put in", i) 26. compute_c += 1 27. break 28. 29. if flag: 30. not_used.append(each_tenant) 31. 32. return result, not_used, building, profit

Kode 26: menjalankan kode 25

1. result, not_used, leftover, profit = solve_g(tenant, building)

Kode 27: tenant yang dipakai disetiap lantai

1. for floor in result: 2. print([int(tenant[0]) for tenant in floor])