Visual walkthrough — DP problems — Fibonacci, coin change (count + min), 0 - 1 knapsack
3.7.9 · D2· Coding › Algorithm Paradigms › DP problems — Fibonacci, coin change (count + min), 0 - 1 kn
Step 0 — Actual sawaal kya hai?
Koi bhi math se pehle, situation imagine karo.
Figure dekho: teen items ek bag ke bahar rakhe hain jis par "capacity " likha hai. Hume har ek ke liye decide karna hai — andar ya bahar. Yeh possible subsets hain — ke liye ek billion hota hai. Hum chahte hain in sab ko check karne se zyada smart approach use karein.
Step 1 — Choice ko ek repeatable sawaal mein badlo
KYA. Hum ek waqt mein EK item attack karte hain. Items ko item 1, item 2, …, item ke order mein lagaao. Item ke saamne khade ho aur ek simple haan/na sawaal poochho: kya main item bag mein daalta hun?
KYUN. Haan/na sawaal ke sirf do branches hote hain. Agar hum "best value using items with a bag of size " ko sirf "best value using items " dekh ke solve kar sakte hain, toh humne ek item problem se hataa diya — ek strictly chota problem jo same shape ka hai. Dynamic programming ka yahi poora trick hai: recursion jahan har call original ka ek chota version hota hai.
PICTURE.
Tree mein pehla fork dikhta hai. Left branch (blue) = "item skip karo". Right branch (orange) = "item lo". Notice karo ki dono children ab sirf items ke baare mein baat karte hain — item khatam ho jaata hai jis waqt hum decide karte hain. Yahi sab kuch ka beej hai.
Hum chote problem ke answer ko yeh naam dete hain:
Term by term:
- — kitne items hum consider karne ki permission rakhte hain (ek prefix ).
- — abhi bag mein kitni capacity baaki hai kharch karne ke liye, .
- — woh number jo hum dhundh rahe hain: in dono limits ke andar maximum value jo mil sakti hai.
Step 2 — "Skip" branch
KYA. Maan lo hum item nahi lete.
KYUN. Agar item kabhi andar nahi jaata, toh jo bhi value humein milegi woh poori tarah items se aayegi, aur bag capacity unchanged rahegi — abhi bhi . Toh hum best yahi kar sakte hain jo ek kam item aur same room ke saath pehle se kar sakte the:
- — item menu se chala gaya, toh hum previous prefix par wapas jaate hain.
- (unchanged) — skip karne mein koi weight nahi lagta, toh capacity same rehti hai.
PICTURE.
Blue arrow seedha ek row upar (row se row tak) jaata hai aur same column mein rehta hai. Seedha upar = "ek kam item"; same column = "capacity kharch nahi hui". Woh vertical arrow hi skip rule hai.
Step 3 — "Take" branch
KYA. Ab maan lo hum item lete hain.
KYUN. Jis waqt item bag mein jaata hai, do cheezein hoti hain:
- Hume uski value milti hai.
- Hum apni capacity mein se kharch karte hain, sirf baaki rehti hai baaki sab ke liye. Aur "baaki sab" items se hi aana chahiye (kyunki item use ho gaya — yeh 0/1 rule hai: doosri copy nahi). Toh:
- — item ko andar rakhne ka reward; ek baar add hota hai.
- — phir se ek row neeche aate hain, kyunki item reuse nahi ho sakta.
- — bag mein ab kam jagah hai; hum sub-problem se reduced capacity ke baare mein poochh rahe hain.
Guard condition. Yeh branch tab hi kaam ka hai jab item fit ho: hamein chahiye . Agar hai toh item current bag ke liye bahut bhaari hai, toh "take" impossible hai aur sirf skip branch bachta hai.
PICTURE.
Orange arrow ek row upar AND columns left jaata hai (column se column tak), phir hum upar se add karte hain. Upar = kam items; left = capacity kharch hui; "" label arrow par chadha hai = collect ki gayi value.
Step 4 — Combine: dono branches mein se better lo
KYA. ke liye hamare paas do candidate values hain: skip value aur take value. Jo bada ho, woh rakhte hain, kyunki hum maximum value chahte hain.
kyun, kyun nahi? Yeh do branches ek hi cell ke liye mutually exclusive decisions hain — item ya to andar hai ya bahar, kabhi dono nahi. Toh hum inhe add nahi karte; winner choose karte hain. exactly yeh jawaab deta hai — "kaunsa ek decision mujhe zyada amir banata hai?"
PICTURE.
Steps 2 aur 3 ke dono arrows ab same target cell (green) mein feed hote hain. Chota "" gate oonchi bar rakhta hai. Poori table ka har cell isi ek gate se bharta hai — yahi poora algorithm hai.
Base row. Row ka matlab hai "zero items allowed". Koi item nahi toh kuch bhi nahi rakh sakte, toh value hai har capacity ke liye: . Yahi woh floor hai jis par poori table tikhi hai.
Step 5 — Poori table bharo, ek real example dekho
KYA. Row by row, left to right, sirf do arrows use karke bharo. Parent se example:
KYUN row order. Har cell sirf row dekhti hai (dono arrows upar jaate hain). Toh jab tak current row shuru karne se pehle previous row complete ho, har zaroorat ki value pehle se ready hai. Koi cell read hone se pehle likhi nahi jaati.
PICTURE.
Colour-shaded grid finished table hai. Bottom-right corner trace karo . Winning path (highlighted) item 2 (weight 3, value 4) aur item 3 (weight 4, value 5) lene se aayi: weight exactly, value. Kyunki har "take" arrow ek row drop karta hai, item 2 aur item 3 mein se har ek ek baar use hota hai — 0/1 ka vaada automatically pura hota hai.
Step 6 — Do rows ko ek mein squeeze karo (aur loop reverse kyun hota hai)
KYA. Notice karo ki har naya row sirf directly upar wala row padhta hai. Toh hume kabhi poori 2D grid ki zaroorat nahi — ek 1D array dp[w] jo hum overwrite karte jaate hain jab bhi koi item process karte hain, woh kaafi hai.
KYUN inner loop reverse karo. Jab hum ek single row in-place overwrite karte hain, toh jo cell hum padhte hain, , usme abhi bhi puraani (previous-item) value honi chahiye — kabhi bhi freshly updated current-item value nahi. Agar hum left→right jaayein, toh hum ko padhne se pehle update kar denge, isse item do baar ghus sakta hai. Right→left jaana ( se tak neeche) guarantee karta hai ki abhi bhi previous item ki value hai jab hum use karte hain.
PICTURE.
Top strip: forward iteration — red arrow left mein ek aisi cell padhta hai jo is round mein already refresh ho chuki hai, toh item phir se ghus jaata hai (yeh unbounded knapsack hai, dekho Unbounded Knapsack and Rod Cutting). Bottom strip: backward iteration — green arrow hamesha ek "puraani" cell padhta hai, toh har item zyada se zyada ek baar andar jaata hai. Same code, bas ek loop direction ka fark.
Step 7 — Har edge case, dikhaya gaya
KYA & KYUN. Ek sahi derivation weird inputs mein bhi survive karni chahiye. Yeh rahi woh cases:
- (bag kuch nahi rakh sakta): take branch ko chahiye, positive weights ke liye impossible, toh har cell hai. Answer . (leftmost panel)
- Koi item nahi (): base row hi poori table hai; answer . (second panel)
- Ek item bag se zyada bhaari (): uska take arrow column par jaayega, jo exist nahi karta — toh woh item kabhi nahi liya ja sakta aur sirf uska skip arrow fire karta hai. (third panel — item greyed out dikhaya gaya hai)
- Zero-value item (): ise lene se milta hai lekin weight khaata hai, toh ise tabhi pick karega jab koi nuksan na ho; yeh optimum ko kabhi hurt nahi karta. (rightmost panel)
- Saare items ek saath fit ho jaate hain (): har take branch available hai, toh optimum simply hai — bag kabhi bottleneck nahi banta.
Kyunki recurrence max(skip, take-if-fits) hai all-zeros base ke saath, in mein se kisi case ke liye special code ki zaroorat nahi — yeh sab same do arrows se nikal aate hain. Yahi robustness hai — ise memorize karne ki jagah derive karne ka yeh faida hai.
Ek-picture summary
Ek target cell, do arrows, ek gate, zeros ki ek base row — ek grid mein repeat, phir ek single backward-swept array mein fold kar diya. Is page par sab kuch wahi picture hai.
Recall Feynman retelling — walkthrough ko ek 12-saal ke bacche ko samjhao
Apne toys line karo. Ek backpack lo jo ek certain weight rakh sakta hai. Pehle toy ke paas jao aur do cheezein poochho: "Agar main ise chod dun, toh pichhle toys aur itni room ke saath main kitna khush hounga?" — yeh grid mein seedha upar dekhna hai. "Agar main ise uthaa lun, toh mujhe uske fun points milenge lekin backpack mein pehle wale toys ke liye kam room bachega" — yeh upar-aur-left dekhna hai, phir fun points add karna. Jo jawaab tumhe zyada khush kare, wahi rakho. Yeh har toy ke saath har possible room amount ke liye karo, har jawaab ek sticky note par likhte jao taaki kabhi redo na karo. Jab ek sticky-note row se kaam chalao paper bachane ke liye, use sabse badi room se sabse choti room tak bharo, taaki kabhi ek hi toy do baar count na ho. Aakhri sticky note, bottom-right, tumhari best possible khushi hai.
Recall
"Take" arrow row par kyun jaata hai, row par kyun nahi? ::: Kyunki 0/1 knapsack mein har item zyada se zyada ek baar use hota hai; item lene ke baad hume sirf pehle ke items ke saath continue karna hai. Dono branches ko add karne ki jagah kyun? ::: Skip aur take same cell ke do mutually exclusive decisions hain; hum better wala pick karte hain, dono nahi karte. 1D version mein weight se tak iterate kyun karte hain? ::: Taaki jab padhte hain tab usme abhi bhi previous item ki value ho, ek item ko do baar lene se rokne ke liye. kya hai aur kyun? ::: Saare ke liye — zero items allowed hone par kuch pack nahi kar sakte, toh koi value nahi.
Yeh bhi dekho: Tabulation vs Memoization · Time and Space Complexity · Subset Sum and Partition Problems · Greedy Algorithms · parent topic.