Disjoint Set Union — গ্রামের রাস্তা মেরামতের পরিকল্পনা¶
কয়েকটি গ্রামের মধ্যে পুরোনো রাস্তা আছে। প্রথমে প্রতিটি পুরোনো রাস্তা যোগ হওয়ার পরে কয়টি আলাদা connected group থাকছে তা জানাবেন। তারপর প্রস্তাবিত নতুন রাস্তার মধ্যে সর্বনিম্ন মোট খরচে সব গ্রাম যুক্ত করার পরিকল্পনা দেবেন। প্রথম ধাপের connectivity-ই দ্বিতীয় ধাপের starting state।
কোর্সের সঙ্গে সম্পর্ক: Graph connectivity ও greedy reasoning-এর বিস্তার। Screenshot-এর module নাম দেখে DSU বা Kruskal-কে Microsoft কোর্সের নিশ্চিত আলাদা lesson বলা হচ্ছে না; এখানে এগুলো অতিরিক্ত অনুশীলন।
১. আগে যা পড়বেন¶
| ক্রম | উপকরণ | প্রস্তুতির লক্ষ্য |
|---|---|---|
| ১ | DSU ধারণা, ধাপে ধাপে চিত্র | Parent pointer এবং representative কী |
| ২ | Find if path exists | একই root মানে connectivity |
| ৩ | Redundant connection | একই group-এ edge দিলে cycle তৈরি হয় |
| ৪ | Road construction | Component count ও largest component বজায় রাখা |
| ৫ | Make network connected | সব group জুড়তে অন্তত components-1 edge কেন |
প্রথমে ৪টি node-এ তিনটি union হাতে করুন। Parent array-এর shape আর মূল road graph-এর shape একই হওয়া দরকার নেই—এই পার্থক্য বুঝে নিন।
২. সমস্যা ও contract¶
road_repair(n, existing, candidates) লিখুন।
- Village ID
0..n-1; রাস্তা undirected। শুরুতে সব village আলাদা। existing-এর প্রতিটি(u, v)input order-এ যোগ করুন। প্রতিবারjoinedঅর্থ সত্যিই দুই আলাদা group যুক্ত হয়েছে কি না,componentsওlargestরিপোর্ট করুন।candidates-এর(u, v, cost)নতুন রাস্তা তৈরির সম্ভাবনা। পুরোনো রাস্তা free; সেগুলো বাদ দেওয়া যাবে না। প্রয়োজনীয় candidate বেছে সব village connected করুন এবং minimum total cost দিন।- সমান cost হলে normalized
(min(u,v), max(u,v))অনুযায়ী edge বাছুন। - যদি সব village জোড়া না যায়,
possible=False,cost=Noneদিন।repairsতখন minimum-cost spanning forest-এর edge; সম্পূর্ণ সফল repair plan নয়।clusters-এ শেষের connected group-গুলো থাকবে।
সীমা: 1 ≤ n ≤ 100,000, existing ও candidate মিলিয়ে সর্বোচ্চ 200,000 edge, integer cost 0..10⁹। Duplicate road ও self-loop বৈধ; এগুলো নতুন group না জুড়লে উপেক্ষা হবে। Invalid vertex, n ≤ 0 বা negative cost-এ ValueError।
flowchart LR
a["0"] --- b["1"]
b --- c["2"]
a --- c
c -. "নতুন: 4" .- d["3"]
d -. "নতুন: 2" .- e["4"]পুরোনো road-এর পরে component count 4, 3, 3; largest size 2, 3, 3। তৃতীয় road নতুন group জোড়ে না। প্রথমে cost 2-এর 3–4, তারপর cost 4-এর 2–3 নিলে সব গ্রাম যুক্ত; total 6।
{
"history": [
{"joined": True, "components": 4, "largest": 2},
{"joined": True, "components": 3, "largest": 3},
{"joined": False, "components": 3, "largest": 3},
],
"possible": True,
"cost": 6,
"repairs": [(3, 4, 2), (2, 3, 4)],
"clusters": [[0, 1, 2, 3, 4]],
}
৩. Guided milestones¶
A — DSU-এর দুটি operation¶
find(x) ও union(a,b) লিখুন। find-এ path compression বা path halving, union-এ ছোট group-কে বড় group-এর নিচে লাগান। union সত্যিই merge করলে True, একই root হলে False।
Invariant: root-এর size তার group-এর node count। Non-root-এর পুরোনো size query-র উত্তর নয়। Checkpoint: union(0,1)-এর পরে find(0)==find(1) এবং root size 2।
B — পুরোনো রাস্তার online report¶
components=n, largest=1 দিয়ে শুরু করুন। Successful union হলে component count এক কমান, merged size দিয়ে largest update করুন। প্রতিটি existing edge-এর পরে report লিখুন।
Checkpoint: (0,1),(1,2),(0,2)-এ শেষ union False; count দ্বিতীয়বারের তুলনায় কমবে না।
C — একই DSU-তে Kruskal repair¶
Candidate-গুলো (cost, u, v) অনুযায়ী sort করুন। Edge দুই আলাদা group জুড়লে গ্রহণ করুন। পুরোনো DSU ফেলে নতুন DSU বানাবেন না—তাহলে আগে থাকা রাস্তার সুবিধা হারাবেন।
Invariant: গৃহীত নতুন edge দুই existing component-কে যুক্ত করে; অপ্রয়োজনীয় cycle কিনছে না। Hint: সবচেয়ে কম খরচের crossing edge নেওয়া নিরাপদ—এটাই Kruskal-এর cut reasoning।
Checkpoint: example-এ 3–4 নেওয়ার পরে component 2; 2–3 নিলে 1; cost 8 ও 10-এর proposal আর লাগবে না।
D — সফলতা ও final group audit¶
প্রতিটি village-এর find করে group বানান। Village-গুলো ascending রাখুন; group-গুলো smallest member অনুযায়ী সাজান। Component এক না হলে success report দেবেন না।
Checkpoint: n=4, proposal শুধু (0,1,2),(2,3,3) হলে group [[0,1],[2,3]], cost=None। Forest-এর edge আছে মানেই সব গ্রাম connected নয়।
৪. Reference ব্যাখ্যা¶
Connectivity এবং minimum cost কেন ঠিক থাকে
DSU প্রতিটি সময় পর্যন্ত যুক্ত হওয়া village-গুলোর partition ধরে। Cycle edge-এ union ব্যর্থ হওয়া কোনো ত্রুটি নয়; নতুন connectivity নেই বলে count অপরিবর্তিত থাকে।
Existing component-গুলোকে একটি করে super-node ভাবলে বাকি সমস্যা minimum spanning tree। Kruskal-এর কম খরচের non-cycle edge নির্বাচন সেই contracted graph-এ minimum cost দেয়। সব super-node জোড়া অসম্ভব হলে forest পাওয়া যায়; সেজন্য possible আলাদা।
৫. Test, complexity ও সীমাবদ্ধতা¶
Repository root থেকে চালান; download করলে দুই ফাইল practice/-এ রাখুন।
৮টি test method example, one village, already connected, disconnected proposals, duplicate/zero-cost road, union-size invariant ও invalid input দেখে। ৬০টি seeded ছোট graph-এ সব candidate subset enumerate করে সত্যিকারের minimum cost-এর সঙ্গে ফল মেলায়।
n village, m existing edge, p candidate হলে sorting O(p log p); DSU operation মোট amortized O((n+m+p) α(n)), final group sorting সর্বোচ্চ O(n log n)। Space O(n+m+p) যদি input, proposal copy ও report সব ধরা হয়। α(n) inverse Ackermann function; বাস্তবে খুব ধীরে বাড়ে।
| ব্যবহার হয়েছে | এই lab-এ নেই |
|---|---|
| Path compression, union by size | Rollback DSU, persistent DSU |
| Connectivity, redundant edge | Edge delete করে dynamic connectivity |
| Component size ও count | Accounts merge-এর string-to-ID modeling |
| Kruskal minimum-cost repair | Making a large island-এর neighbor-root deduplication |
বাকি pattern-এর জন্য সব DSU problem অনুসরণ করুন।