18-bo‘lim
Ochko'z algoritmlar
Ochko'z yondashuv, u qachon ishlaydi va qachon ishlamaydi, mashg'ulotlarni rejalashtirish va Huffman kodlash.
Ushbu bo‘lim mundarijasi
Ochko'z algoritm juda sodda qoidaga amal qiladi: har bir qadamda shu paytdagi eng yaxshi variantni tanla va orqaga qaytma.
Ba'zan bu optimal javob beradi, ba'zan esa - yo'q. Farqni bilish muhim.
Ochko'z yondashuv mohiyati #
| Yondashuv | Strategiya | Narxi |
|---|---|---|
| To'liq izlash | Barcha variantni sinash | O(2ⁿ) - juda qimmat |
| Dinamik dasturlash | Barcha qism masalalarni yechish | O(n·W) - o'rtacha |
| Ochko'z | Har qadamda eng yaxshisini olish | O(n log n) - arzon |
Ochko'z algoritm eng tez, lekin to'g'ri javobni kafolatlamaydi.
Ishlaydigan misol: tangalarni maydalash #
O'zbekiston tangalari uchun ochko'z yondashuv to'g'ri ishlaydi:
def ochkoz_maydala(nominallar, summa):
"""Har safar eng katta tangani oladi. O(n log n)."""
natija = []
qolgan = summa
for tanga in sorted(nominallar, reverse=True):
soni = qolgan // tanga
if soni:
natija.extend([tanga] * soni)
qolgan -= tanga * soni
return natija if qolgan == 0 else None
nominallar = [1, 5, 10, 25, 50, 100]
for summa in [63, 87, 130]:
tangalar = ochkoz_maydala(nominallar, summa)
print(f"{summa:>4} so'm -> {len(tangalar)} ta tanga: {tangalar}")
63 so'm -> 6 ta tanga: [50, 10, 1, 1, 1]
87 so'm -> 6 ta tanga: [50, 25, 10, 1, 1]
130 so'm -> 3 ta tanga: [100, 25, 5]
Ishlamaydigan misol #
def taqqosla(nominallar, summa):
"""Ochko'z va DP yechimlarini taqqoslaydi."""
ochkoz = ochkoz_maydala(nominallar, summa)
CHEKSIZ = float("inf")
jadval = [0] + [CHEKSIZ] * summa
for joriy in range(1, summa + 1):
for tanga in nominallar:
if tanga <= joriy:
jadval[joriy] = min(jadval[joriy], jadval[joriy - tanga] + 1)
optimal = jadval[summa]
ochkoz_soni = len(ochkoz) if ochkoz else CHEKSIZ
holat = "to'g'ri" if ochkoz_soni == optimal else "XATO"
print(f" Nominallar {nominallar}, summa {summa}")
print(f" Ochko'z: {ochkoz_soni} ta {ochkoz}")
print(f" Optimal: {optimal} ta")
print(f" Natija: {holat}\n")
taqqosla([1, 5, 10, 25], 30)
taqqosla([1, 3, 4], 6)
taqqosla([1, 15, 25], 30)
Nominallar [1, 5, 10, 25], summa 30
Ochko'z: 2 ta [25, 5]
Optimal: 2 ta
Natija: to'g'ri
Nominallar [1, 3, 4], summa 6
Ochko'z: 3 ta [4, 1, 1]
Optimal: 2 ta
Natija: XATO
Nominallar [1, 15, 25], summa 30
Ochko'z: 6 ta [25, 1, 1, 1, 1, 1]
Optimal: 2 ta
Natija: XATO
Ochko'z yechim to'g'ri ekanini matematik isbotlash kerak. Aks holda u ba'zi kirish ma'lumotlarida jim ravishda noto'g'ri javob beradi - va bu xatoni topish juda qiyin.
Agar isbot topa olmasangiz, dinamik dasturlash ishlating: sekinroq, lekin to'g'ri.
Ochko'z ishlashi uchun ikki shart #
| Shart | Ma'nosi |
|---|---|
| Ochko'z tanlov xossasi | Lokal optimal tanlov global optimalga olib boradi |
| Optimal qism tuzilma | Masalaning yechimi qism masalalar yechimidan iborat |
Ishlaydigan klassik masala: mashg'ulotlarni rejalashtirish #
Bitta auditoriya bor. Har bir mashg'ulotning boshlanish va tugash vaqti ma'lum. Eng ko'p mashg'ulotni qanday joylashtirish mumkin?
Ochko'z qoidasi: eng erta tugaydiganni tanla.
def mashgulotlarni_rejalashtir(mashgulotlar):
"""Eng ko'p mashg'ulotni joylashtiradi. O(n log n)."""
# Tugash vaqti bo'yicha saralaymiz - ochko'z tanlovning kaliti
tartiblangan = sorted(mashgulotlar, key=lambda m: m[2])
tanlangan = []
oxirgi_tugash = 0
for nomi, boshlanish, tugash in tartiblangan:
if boshlanish >= oxirgi_tugash:
tanlangan.append((nomi, boshlanish, tugash))
oxirgi_tugash = tugash
return tanlangan
mashgulotlar = [
("Python darsi", 9, 11),
("Algoritmlar", 10, 12),
("Ma'lumotlar bazasi", 11, 13),
("Veb dasturlash", 12, 14),
("Ingliz tili", 13, 15),
("Matematika", 9, 14),
]
tanlangan = mashgulotlarni_rejalashtir(mashgulotlar)
print(f"{'Mashg‘ulot':<22}{'Vaqt':>12}")
print("-" * 34)
for nomi, boshlanish, tugash in tanlangan:
print(f"{nomi:<22}{boshlanish:>6}:00 - {tugash}:00")
print("-" * 34)
print(f"Jami {len(tanlangan)} ta mashg'ulot joylashtirildi "
f"({len(mashgulotlar)} tadan)")
Mashg'ulot Vaqt
----------------------------------
Python darsi 9:00 - 11:00
Ma'lumotlar bazasi 11:00 - 13:00
Ingliz tili 13:00 - 15:00
----------------------------------
Jami 3 ta mashg'ulot joylashtirildi (6 tadan)
Mashg'ulot qanchalik erta tugasa, qolganlar uchun shuncha ko'p vaqt qoladi. Bu intuitiv, lekin matematik isboti ham bor: har qanday optimal yechimdagi birinchi mashg'ulotni eng erta tugaydiganiga almashtirsak, yechim yomonlashmaydi.
E'tibor bering: "eng qisqa" yoki "eng erta boshlanadigan" qoidalari ishlamaydi. Yuqoridagi misolda "Matematika" (9-14) eng erta boshlanadi, lekin uni tanlash faqat 1 ta mashg'ulot berardi.
Ishlaydigan masala: fraksion ryukzak #
O'tgan bo'limdagi ryukzak masalasi DP talab qilgan edi. Lekin agar buyumlarni bo'lish mumkin bo'lsa (qum, un, benzin), ochko'z yondashuv optimal ishlaydi:
def fraksion_ryukzak(buyumlar, quvvat):
"""Buyumlarni bo'lish mumkin bo'lgan ryukzak. O(n log n)."""
# Birlik og'irlik uchun qiymat bo'yicha saralaymiz
tartiblangan = sorted(buyumlar, key=lambda b: b[2] / b[1], reverse=True)
jami_qiymat = 0.0
tanlangan = []
qolgan = quvvat
for nomi, ogirlik, qiymat in tartiblangan:
if qolgan <= 0:
break
if ogirlik <= qolgan:
tanlangan.append((nomi, ogirlik, qiymat, 100))
jami_qiymat += qiymat
qolgan -= ogirlik
else:
ulush = qolgan / ogirlik
tanlangan.append((nomi, qolgan, qiymat * ulush, ulush * 100))
jami_qiymat += qiymat * ulush
qolgan = 0
return jami_qiymat, tanlangan
mahsulotlar = [
("Zafaron", 2, 12000),
("Asal", 5, 8000),
("Yong'oq", 8, 6000),
("Un", 10, 2000),
]
QUVVAT = 12
qiymat, tanlangan = fraksion_ryukzak(mahsulotlar, QUVVAT)
print(f"{'Mahsulot':<12}{'Og‘irlik':>10}{'Ulush':>9}{'Qiymat':>11}")
print("-" * 42)
for nomi, ogirlik, narx, ulush in tanlangan:
print(f"{nomi:<12}{ogirlik:>8} kg{ulush:>8.0f}%{narx:>11,.0f}")
print("-" * 42)
print(f"{'JAMI':<12}{QUVVAT:>8} kg{'':>9}{qiymat:>11,.0f}")
Mahsulot Og'irlik Ulush Qiymat
------------------------------------------
Zafaron 2 kg 100% 12,000
Asal 5 kg 100% 8,000
Yong'oq 5 kg 62% 3,750
------------------------------------------
JAMI 12 kg 23,750
| 0/1 ryukzak | Fraksion ryukzak | |
|---|---|---|
| Buyumni bo'lish | Mumkin emas | Mumkin |
| To'g'ri yondashuv | DP | Ochko'z |
| Murakkablik | O(n·W) | O(n log n) |
Farq bitta so'zda, lekin yondashuv butunlay boshqa.
Huffman kodlash #
Ochko'z algoritmning eng chiroyli qo'llanishi - ma'lumotni siqish. G'oya: tez-tez uchraydigan belgiga qisqa kod ber.
import heapq
from collections import Counter
class HuffmanTugun:
def __init__(self, belgi, chastota, chap=None, ong=None):
self.belgi = belgi
self.chastota = chastota
self.chap = chap
self.ong = ong
def __lt__(self, boshqa):
return self.chastota < boshqa.chastota
def huffman_kodlari(matn):
"""Har bir belgi uchun optimal ikkilik kod hosil qiladi."""
chastotalar = Counter(matn)
if len(chastotalar) == 1: # maxsus holat
return {next(iter(chastotalar)): "0"}
uyum = [HuffmanTugun(belgi, soni) for belgi, soni in chastotalar.items()]
heapq.heapify(uyum)
# Har safar eng kam uchraydigan ikkitasini birlashtiramiz
while len(uyum) > 1:
birinchi = heapq.heappop(uyum)
ikkinchi = heapq.heappop(uyum)
yangi = HuffmanTugun(None, birinchi.chastota + ikkinchi.chastota,
birinchi, ikkinchi)
heapq.heappush(uyum, yangi)
# Daraxt bo'ylab yurib kodlarni yig'amiz
kodlar = {}
def yur(tugun, kod=""):
if tugun is None:
return
if tugun.belgi is not None:
kodlar[tugun.belgi] = kod or "0"
return
yur(tugun.chap, kod + "0")
yur(tugun.ong, kod + "1")
yur(uyum[0])
return kodlar
matn = "dasturlash dasturlash algoritm"
kodlar = huffman_kodlari(matn)
chastotalar = Counter(matn)
print(f"{'Belgi':<8}{'Chastota':>10}{'Kod':>10}{'Bit':>6}")
print("-" * 34)
for belgi, kod in sorted(kodlar.items(), key=lambda j: -chastotalar[j[0]]):
korinish = repr(belgi) if belgi == " " else belgi
print(f"{korinish:<8}{chastotalar[belgi]:>10}{kod:>10}{len(kod):>6}")
oddiy_bitlar = len(matn) * 8
huffman_bitlar = sum(chastotalar[b] * len(k) for b, k in kodlar.items())
print("-" * 34)
print(f"Oddiy kodlash (8 bit): {oddiy_bitlar:>6} bit")
print(f"Huffman kodlash: {huffman_bitlar:>6} bit")
print(f"Siqilish darajasi: {(1 - huffman_bitlar / oddiy_bitlar):>6.1%}")
Belgi Chastota Kod Bit
----------------------------------
a 6 00 2
s 4 010 3
t 3 100 3
r 3 101 3
' ' 2 1100 4
d 2 1101 4
u 2 1110 4
l 3 011 3
h 2 1111 4
g 1 11110 5
o 1 11111 5
i 1 111100 6
m 1 111101 6
----------------------------------
Oddiy kodlash (8 bit): 240 bit
Huffman kodlash: 108 bit
Siqilish darajasi: 55.0%
Matn hajmi ikki barobardan ko'proq kamaydi. Bu algoritm ZIP, JPEG va MP3 formatlarida ishlatiladi.
Ochko'z algoritmlar ro'yxati #
| Algoritm | Masala | To'g'rimi |
|---|---|---|
| Dijkstra | Eng qisqa yo'l (musbat vaznlar) | Ha |
| Prim, Kruskal | Minimal ostki daraxt | Ha |
| Huffman | Optimal siqish | Ha |
| Mashg'ulotlarni rejalashtirish | Maksimal soni | Ha |
| Fraksion ryukzak | Maksimal qiymat | Ha |
| 0/1 ryukzak | Maksimal qiymat | Yo'q |
| Tangalarni maydalash | Minimal tangalar | Nominalga bog'liq |
| Sotuvchi masalasi (TSP) | Eng qisqa marshrut | Yo'q |
- Ochko'z yechimni o'ylab ko'ring - u sodda va tez.
- Uni buzadigan misol topishga urinib ko'ring.
- Topsangiz → DP ishlating.
- Topmasangiz va isbotlay olsangiz → ochko'z ishlating.
Intervyularda ko'pincha aynan shu fikrlash jarayoni baholanadi, javobning o'zi emas.
- Benzin quyish masalasi: A dan B ga borish uchun eng kam necha marta to'xtash kerak? Ochko'z yechim yozing va nima uchun to'g'ri ishlashini tushuntiring.
[1, 3, 4]nominallari uchun ochko'z algoritm xato beradigan yana ikkita summa toping.- Huffman kodlash uchun dekodlash funksiyasini yozing.
- Mashg'ulotlarni rejalashtirishning
kta auditoriyali variantini yeching.
Xulosa #
- Ochko'z algoritm har qadamda lokal eng yaxshi tanlovni qiladi va orqaga qaytmaydi.
- U juda tez (odatda O(n log n)), lekin har doim ham optimal emas.
- Ishlashi uchun ochko'z tanlov xossasi isbotlanishi kerak.
- Mashg'ulotlarni rejalashtirishda to'g'ri qoida - eng erta tugaydiganni tanlash.
- Fraksion ryukzak - ochko'z, 0/1 ryukzak - DP.
- Huffman kodlash - ochko'z algoritmning amaliy va keng tarqalgan qo'llanishi.
Keyingi bo'limda eng mashhur ochko'z algoritm - Dijkstra bilan tanishamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.