পাঠ ১৯ · ৪৪-এর মধ্যে · মডিউল ৪
Home / Courses / Discrete Mathematics / রিপ্রেজেন্টেশন ও কানেক্টিভিটি

গ্রাফ রিপ্রেজেন্টেশন ও কানেক্টিভিটি

Graph representation & connectivity
৮ মিনিট পড়া শুরু · Beginner Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • Adjacency matrix ও adjacency list রিপ্রেজেন্টেশনের গঠন ও ট্রেডঅফ
  • Walk, trail, path-এর সংজ্ঞা ও পার্থক্য
  • Connected graph ও connected component-এর সংজ্ঞা
  • BFS কীভাবে কানেক্টিভিটি যাচাইয়ে ব্যবহৃত হয় (concept-level)
  • Python-এ BFS-ভিত্তিক কানেক্টিভিটি চেকার — সংযুক্ত ও বিচ্ছিন্ন উভয় গ্রাফে পরীক্ষা

১ · গ্রাফ কীভাবে সংরক্ষণ করা হয়?

L18-এ আমরা গ্রাফকে গাণিতিকভাবে সংজ্ঞায়িত করেছি। কিন্তু কম্পিউটারে একটি গ্রাফ প্রকৃতপক্ষে সংরক্ষণ করতে দুটি প্রধান পদ্ধতি ব্যবহৃত হয় —

Adjacency MatrixAdjacency Matrixএকটি $n \times n$ গ্রিড, যেখানে row $i$, column $j$-এর মান 1 হয় যদি vertex $i$ ও $j$-এর মধ্যে edge থাকে, নাহলে 0।
$n \times n$ গ্রিড — এন্ট্রি 1 যদি edge থাকে, নাহলে 0। edge আছে কিনা তা $O(1)$ সময়ে জানা যায়, কিন্তু জায়গা লাগে $O(n^2)$ — sparse গ্রাফে অপচয়।
Adjacency List
প্রতিটি vertex-এর একটি তালিকা — তার প্রতিবেশীরা কারা। জায়গা লাগে $O(\deg(v))$ — sparse গ্রাফের জন্য (কম edge থাকলে) অনেক বেশি জায়গা-সাশ্রয়ী।
বাস্তব-জীবনের বেশিরভাগ গ্রাফ (সোশ্যাল নেটওয়ার্ক, রোড নেটওয়ার্ক) sparse — অর্থাৎ সম্ভাব্য edge-এর তুলনায় প্রকৃত edge অনেক কম। তাই বাস্তবে adjacency list-ই বেশি ব্যবহৃত হয়। আমরা এই কোর্সের সব code cell-এ adjacency list (Python dict) ব্যবহার করব।

২ · Walk, Trail, ও Path

একটি গ্রাফে এক vertex থেকে আরেক vertex-এ যাওয়ার "রাস্তা" বোঝাতে তিনটি ভিন্ন, সুনির্দিষ্ট পরিভাষা ব্যবহৃত হয় —

  • WalkWalkvertex ও edge-এর যেকোনো ক্রম যেখানে পরপর প্রতিটি জোড়া edge দ্বারা সংযুক্ত — vertex ও edge পুনরাবৃত্তি করা যায়। — vertex-edge-vertex-...-এর যেকোনো ক্রম, vertex বা edge পুনরাবৃত্তি করা যায়।
  • Trail — একটি walk যেখানে কোনো edge পুনরাবৃত্তি হয় না (vertex পুনরাবৃত্তি হতে পারে)।
  • Path — একটি trail যেখানে কোনো vertex-ও পুনরাবৃত্তি হয় না।

L20-এ আমরা দেখব Euler path মূলত একটি বিশেষ ধরনের trail (প্রতিটি edge ব্যবহার করে, কিন্তু vertex পুনরাবৃত্তি হতে পারে), আর Hamiltonian path একটি প্রকৃত path (প্রতিটি vertex ঠিক একবার)।

৩ · কানেক্টিভিটি

একটি গ্রাফ connected হয় যদি প্রতিটি জোড়া vertex-এর মধ্যে অন্তত একটি path থাকে। যদি কোনো গ্রাফ connected না হয়, তাহলে সেটি কয়েকটি connected componentConnected componentএকটি গ্রাফের সর্বোচ্চ (maximal) connected উপ-গ্রাফ — যে vertex-গুলো নিজেদের মধ্যে path-এর মাধ্যমে পৌঁছানো যায়, কিন্তু বাকি গ্রাফের সাথে নয়।-এ ভাগ হয়ে যায় — প্রতিটি component নিজে সম্পূর্ণ connected, কিন্তু অন্য component-এর সাথে কোনো path নেই।

কানেক্টিভিটি যাচাই — BFS/DFS

একটি গ্রাফ connected কিনা তা যাচাই করার standard পদ্ধতি হলো যেকোনো একটি vertex থেকে BFS (Breadth-First Search) বা DFS (Depth-First Search) চালিয়ে দেখা — সব vertex পৌঁছানো যায় কিনা। যদি সব vertex ভ্রমণ (visit) করা যায়, গ্রাফ connected; নাহলে অভ্রমিত vertex-গুলো অন্য component-এ। এই অ্যালগরিদমগুলোর সম্পূর্ণ বাস্তবায়ন ও জটিলতা বিশ্লেষণ DSA কোর্সের বিষয় — এখানে আমরা শুধু ধারণাটি ব্যবহার করছি।

Python
from collections import deque

def is_connected(graph, start, all_vertices):
    visited = {start}
    queue = deque([start])
    while queue:
        v = queue.popleft()
        for neighbor in graph.get(v, []):
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)
    return visited == set(all_vertices)

# গ্রাফ ১: সংযুক্ত (সবাই একে অপরের সাথে path-এ যুক্ত)
graph_connected = {
    "A": ["B", "C"],
    "B": ["A", "C"],
    "C": ["A", "B", "D"],
    "D": ["C"],
}
vertices1 = ["A", "B", "C", "D"]
print("গ্রাফ ১ সংযুক্ত (connected)?", is_connected(graph_connected, "A", vertices1))

# গ্রাফ ২: বিচ্ছিন্ন — {A,B} ও {C,D} দুটি আলাদা component
graph_disconnected = {
    "A": ["B"],
    "B": ["A"],
    "C": ["D"],
    "D": ["C"],
}
vertices2 = ["A", "B", "C", "D"]
print("গ্রাফ ২ সংযুক্ত (connected)?", is_connected(graph_disconnected, "A", vertices2))

    

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ কখন adjacency matrix, adjacency list-এর চেয়ে ভালো পছন্দ হতে পারে?

যখন গ্রাফটি dense (edge সংখ্যা $|V|^2$-এর কাছাকাছি) অথবা যখন বারবার "এই দুটি vertex-এর মধ্যে edge আছে কি না" এই প্রশ্নের $O(1)$ সময়ে উত্তর দরকার — তখন matrix-এর $O(n^2)$ জায়গার খরচ যুক্তিসঙ্গত, কারণ lookup speed-এর সুবিধা জায়গার খরচকে ছাপিয়ে যায়। বিপরীতে sparse গ্রাফে (যেমন একটি সোশ্যাল নেটওয়ার্ক যেখানে গড়ে প্রতিটি ব্যবহারকারীর কয়েকশ বন্ধু, কিন্তু কোটি কোটি সম্ভাব্য জোড়া) matrix বিশাল পরিমাণ মেমরি অপচয় করবে অধিকাংশ 0 সংরক্ষণ করে।

প্র ০২ একটি walk যেখানে edge পুনরাবৃত্তি নেই কিন্তু vertex পুনরাবৃত্তি আছে — এটি trail নাকি path? উদাহরণ দিন।

এটি একটি trail কিন্তু path নয় — কারণ path-এর শর্ত হলো vertex-ও পুনরাবৃত্তি হবে না। উদাহরণ — একটি চতুর্ভুজাকৃতি গ্রাফে A-B-C-D-A-এর মতো একটি ঘুরপথ যেখানে A দুইবার আসে (একবার শুরুতে, একবার শেষে) কিন্তু কোনো edge দুইবার ব্যবহৃত হয়নি — এটি একটি trail (আসলে একটি circuit, যেহেতু শুরু ও শেষ vertex একই)। L20-এ Euler circuit ঠিক এই ধরনের গঠন — অনেক vertex পুনরাবৃত্তি হতে পারে, কিন্তু কোনো edge নয়।

প্র ০৩ উপরের কোড সেলে গ্রাফ ২-এর জন্য ফলাফল False এসেছে। এর মানে কি গ্রাফ ২-তে কোনো গঠন/সংযোগ নেই?

না — False মানে গ্রাফটি সম্পূর্ণভাবে connected নয়, কিন্তু এর মানে এই নয় যে কোনো সংযোগই নেই। গ্রাফ ২-তে আসলে দুটি সম্পূর্ণ connected component আছে — {A, B} (একটি edge দ্বারা সংযুক্ত) এবং {C, D} (আরেকটি edge দ্বারা সংযুক্ত)। প্রতিটি component-এর ভেতরে সবকিছু connected, কিন্তু দুই component-এর মধ্যে কোনো path নেই — তাই সামগ্রিক গ্রাফ connected নয়। BFS শুধু start vertex-এর component-টুকু ভ্রমণ করতে পারে, বাকিটা নয়।

অনুশীলন

  1. হাতে করুন: {A, B, C} vertex এবং {A-B, B-C} edge-বিশিষ্ট একটি গ্রাফের adjacency matrix হাতে লিখুন (3×3 গ্রিড, row/column ক্রম A,B,C)।

       A B C
    A [0, 1, 0]
    B [1, 0, 1]
    C [0, 1, 0]
    A-B ও B-C-এর সাথে সঙ্গতিপূর্ণভাবে 1, বাকি সব 0 (A-C-এর মধ্যে সরাসরি edge নেই)। লক্ষ্য করুন matrix-টি symmetric — কারণ গ্রাফটি undirected।

  2. পরীক্ষা করুন: উপরের কোড সেলে graph_connected-এ vertex "E" যোগ করুন যার কোনো প্রতিবেশী নেই ("E": []), এবং vertices1-এ "E" যোগ করুন। is_connected এখন কী রিটার্ন করবে এবং কেন?

    রিটার্ন হবে False — কারণ BFS শুধু "A"-এর সাথে সংযুক্ত component ভ্রমণ করে ({A, B, C, D}), কিন্তু বিচ্ছিন্ন vertex "E" কখনো visited সেটে যুক্ত হবে না। তাই visited == set(all_vertices) মিথ্যা হয়ে যাবে — একটি সম্পূর্ণ বিচ্ছিন্ন (isolated) vertex-ও গ্রাফকে disconnected করে দেয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
গ্রাফ — সংজ্ঞা, টার্মিনোলজি ও প্রকারভেদ