Тоо бүрийн хувьд "авах уу, авахгүй юу?" гэж шийдээд бүх 2ⁿ дэд олонлогийг backtracking аргаар гаргана.
Эхлээд жижиг бодлого
{1, 2, 3} олонлогийн бүх дэд олонлогийг гаргая. Тоо бүрийн хувьд "авах уу, авахгүй юу?" гэж асууна. Гурван тоо, тус бүрт хоёр сонголт тул 2 × 2 × 2 = 8 дэд олонлог гарна.
Код "авах" замыг эхэлж үздэг тул хэвлэх дараалал: 1 2 3, 1 2, 1 3, 1, 2 3, 2, 3, хоосон мөр.
Энгийн аргаас санаа руу
Гараар бичихэд эхлээд нэг элементтэй, дараа нь хоёр элементтэйг нь бичдэг. Гэхдээ үүнийг кодонд n-ээс хамааран хэдэн давхар loop болохыг урьдчилан мэдэхгүй.
Гол санаа: тоог нэг нэгээр нь шийдэх. solve(i) нь a[i]-г авах эсэхийг шийднэ. Эхлээд авч cur-д нэмээд цааш явна. Буцаж ирээд түүнийг cur-ээс хасаж, авахгүй замаар явна. "Сонгох, цааш явах, буцааж болиулах" гэсэн энэ загварыг backtracking гэдэг.
Нэр томьёо ба тэмдэглэгээ
- solve(i)
- a[0..i−1]-ийг аль хэдийн шийдсэн. Одоо a[i]-г шийднэ.
- cur
- Одоогийн замд авсан тоонууд.
vector<int>. - backtrack
- Буцаж ирээд сүүлийн сонголтоо болиулах:
cur.pop_back(). - 2ⁿ
- n элементтэй олонлогийн дэд олонлогийн тоо.
{1, 2, 3} олонлогийн бүх дэд олонлогийг олъё. Тоо бүрийн хувьд "авах уу, авахгүй юу?" гэж асууна.
- Space тоглуулах
- ←→ алхам
- −+ хурд
- Ажиллаж буй дуудлага
- Хүлээж буй
- Бэлэн дэд олонлог
- Шалгаж дууссан
Авах уу, авахгүй юу?
{1, 2, 3} олонлогоос хэдэн янзын бүлэг сонгож болох вэ? Тоо бүрийн хувьд "авах уу, авахгүй юу?" гэж асуугаад бүх замаар явна.
Дараа нь юу болох вэ?
Оноо 0 / 00дараалсан зөв, хамгийн их 0
Animation нэг алхам дээр зогсоно. Дараа нь код юу хийх вэ? Таагаад оноо цуглуул! Нэвтрэх хэрэггүй, оноо чинь энэ төхөөрөмж дээр хадгалагдана.
Юунд хэрэгтэй вэ?
Олонлогийн бүх дэд олонлогийг гаргана. Сонгох, цааш явах, буцааж болиулах гэсэн backtracking-ийн чухал загварыг сурна.
Яаж ажилладаг вэ?
1. solve(i) нь a[i]-г авах эсэхийг шийднэ. cur нь одоогоор авсан тоонууд. 2. i == n бол бүх тоог шийдсэн байна. cur доторх тоонуудыг хэвлэнэ. 3. a[i]-г cur-д нэмээд solve(i + 1)-ийг дуудна. Энэ бол "авах" зам. 4. Буцаж ирээд a[i]-г cur дотроос гаргана (backtrack). 5. Дахин solve(i + 1)-ийг дуудна. Энэ бол "авахгүй" зам. Оролт: n, дараагийн мөрөнд n тоо. Хоосон олонлог хоосон мөр болж хэвлэгдэнэ.
Яагаад зөв, хэр хурдан бэ?
Дэд олонлог бүр тоо бүрийн хувьд "авсан" эсвэл "аваагүй" гэсэн n шийдвэрээр тодорхойлогдоно. solve эдгээр шийдвэрийн бүх хослолыг яг нэг удаа үздэг тул дэд олонлог бүр яг нэг удаа хэвлэгдэнэ. cur.pop_back() нь cur-ийг дуудлагын өмнөх байдалд нь буцаадаг тул "авахгүй" зам цэвэр эхэлнэ.
2ⁿ дэд олонлог, тус бүрийг хэвлэхэд n хүртэл тоо: хугацаа O(n · 2ⁿ). n = 20 бол 1 сая дэд олонлог, 20 сая орчим үйлдэл. n = 30 бол тэрбум дэд олонлог, хэт удаан.
Түгээмэл алдаа
cur.pop_back()-ийг мартах. "Авахгүй" зам дээр авсан тоо cur-д үлдээд хариу буруу болно.- Base case-ийг
i > nгэж бичих. Сүүлийн тоог шийдсэн мөч ньi == n. - n том үед бүх дэд олонлогийг гаргах гэж оролдох. n > 25 бол өөр арга хэрэгтэй.
Хязгаарын тохиолдол
- n = 1,
{5}:5ба хоосон мөр хэвлэгдэнэ. - Хоосон дэд олонлог үргэлж хамгийн сүүлд хоосон мөр болж гарна.
- Ижил тоо давтагдвал
{1, 1}гэх мэт ижил дэд олонлог хоёр удаа хэвлэгдэнэ.
Өөрийгөө шалга
4 элементтэй олонлог хэдэн дэд олонлогтой вэ?
Хариу харах
16.
2⁴ = 16, хоосон олонлогийг оруулаад.{1, 2, 3}дээр хэвлэгдэх дөрөв дэх мөр юу вэ?Хариу харах
1. Дараалал нь1 2 3,1 2,1 3,1.
Гурван дадлага
Hint-ээ нээхээс өмнө өөрөө оролдоорой.
1.
{4, 7}дээр solve-ын дуудлагуудыг tree хэлбэрээр зур. Юу хэвлэгдэх вэ?Hint харах
Root нь solve(0), cur = {}. Зүүн тал нь "авах" зам.
Хариу ба тайлбар
Навчнууд зүүнээс баруун тийш {4, 7}, {4}, {7}, {}. Хэвлэгдэх нь
4 7,4,7, хоосон мөр.2.Зөвхөн нийлбэр нь k-тэй тэнцүү дэд олонлогуудыг тоол.
{2, 3, 5}, k = 5 бол хэд вэ?Hint харах
cur-ийн оронд одоогийн нийлбэрийг solve-д дамжуул.
Хариу ба тайлбар
solve(i, s):i == nүедs == kбол cnt-г нэмнэ. Авах замsolve(i + 1, s + a[i]), авахгүй замsolve(i + 1, s). Хариу 2: {2, 3} ба {5}.3.Recursion ашиглахгүйгээр бүх дэд олонлогийг bitmask-аар гарга.
Hint харах
0-ээс 2ⁿ − 1 хүртэлх mask бүрийн i дэх bit нь a[i]-г авсан эсэхийг заана.
Хариу ба тайлбар
for (int mask = 0; mask < (1 << n); mask++)доторif (mask >> i & 1)бол a[i]-г хэвлэнэ. Хугацаа O(n · 2ⁿ) хэвээр.
Жишээ
Оролт
3 1 2 3
Гаралт
1 2 3 1 2 1 3 1 2 3 2 3
Одоо өөрөө бодоод үз
Хичээл
Энэ сэдвийн хичээл удахгүй нэмэгдэнэ.