ภาพรวมปัญหา
กำหนดกราฟ Undirected Graph ที่มี N โหนด (โหนด i มีค่า arr[i-1]) และ M Edge ให้หาผลรวมของค่าต่ำสุด (Minimum Value) ในแต่ละ Connected Component
โหนดที่ไม่มี Edge เชื่อม (Isolated Node) ถือเป็น Component เดียว
ตัวอย่าง
arr = [2, 7, 5, 1, 3] // Node 1=2, Node 2=7, Node 3=5, Node 4=1, Node 5=3
Edges: (1,2), (4,5)
Components:
- Component 1: Nodes {1,2} → Values {2,7} → Min = 2
- Component 2: Nodes {4,5} → Values {1,3} → Min = 1
- Component 3: Node {3} → Values {5} → Min = 5
Sum = 2 + 1 + 5 = 8
อัลกอริทึม: DFS + Visited Array
- สร้าง Adjacency List จาก Edge List
- สร้าง Visited Array ขนาด N
- สำหรับโหนดทุกตัวที่ยังไม่ Visited:
- เริ่ม DFS/BFS จากโหนดนั้น
- หาค่า Minimum ใน Component นี้
- บวกเข้ากับผลรวม Total
- คืนค่า Total Sum
ตัวอย่างโค้ด C++ (DFS Recursive)
#include <iostream> #include <vector> #include <algorithm> #include <climits> using namespace std; const int MAXN = 100005; vectorgraph[MAXN]; bool visited[MAXN]; int values[MAXN]; int dfsMin(int node) { visited[node] = true; int minVal = values[node]; for (int neighbor : graph[node]) { if (!visited[neighbor]) { minVal = min(minVal, dfsMin(neighbor)); } } return minVal; } long long minSumComponents(int n) { long long sum = 0; for (int i = 1; i <= n; i++) { if (!visited[i]) { int componentMin = dfsMin(i); sum += componentMin; } } return sum; } int main() { int n = 5; // Values (1-indexed) values[1] = 2; values[2] = 7; values[3] = 5; values[4] = 1; values[5] = 3; // Edges graph[1].push_back(2); graph[2].push_back(1); graph[4].push_back(5); graph[5].push_back(4); cout << "Sum of minimums = " << minSumComponents(n) << endl; // 8 return 0; }
ตัวอย่างโค้ด C++ (BFS Iterative - กัน Stack Overflow)
#include <iostream> #include <vector> #include <queue> #include <algorithm> #include <climits> using namespace std; long long minSumComponentsBFS(int n, vectorvalues, vector >& graph) { vector visited(n + 1, false); long long sum = 0; for (int i = 1; i <= n; i++) { if (!visited[i]) { int minVal = INT_MAX; queue q; q.push(i); visited[i] = true; while (!q.empty()) { int u = q.front(); q.pop(); minVal = min(minVal, values[u]); for (int v : graph[u]) { if (!visited[v]) { visited[v] = true; q.push(v); } } } sum += minVal; } } return sum; } int main() { int n = 5; vector values = {0, 2, 7, 5, 1, 3}; // 1-indexed vector > graph(n + 1); graph[1].push_back(2); graph[2].push_back(1); graph[4].push_back(5); graph[5].push_back(4); cout << "Sum of minimums (BFS) = " << minSumComponentsBFS(n, values, graph) << endl; return 0; }
ผลลัพธ์ตัวอย่าง
Sum of minimums = 8 Sum of minimums (BFS) = 8
การทำงานขั้นตอน (DFS Trace)
| Step | Node | Action | Component Min | Total Sum |
|---|---|---|---|---|
| 1 | 1 | Start DFS, visit 1,2 | min(2,7)=2 | 2 |
| 2 | 3 | Not visited, isolated | min(5)=5 | 7 |
| 3 | 4 | Start DFS, visit 4,5 | min(1,3)=1 | 8 |
ความซับซ้อนของอัลกอริทึม
- เวลา: O(N + M) - เยี่ยมชมทุกโหนดและ Edge ครั้งเดียว
- พื้นที่: O(N + M) - Adjacency List + Visited Array + Stack/Queue
กรณีทดสอบเพิ่มเติม
// Test 1: Fully Connected
n=4, values={10,20,30,40}, edges={(1,2),(2,3),(3,4),(4,1)}
// 1 Component: min=10, Sum=10
// Test 2: No Edges
n=3, values={5,3,8}, edges={}
// 3 Components: 5+3+8=16
// Test 3: Star Graph
n=5, values={100,1,2,3,4}, edges={(1,2),(1,3),(1,4),(1,5)}
// 1 Component: min=1, Sum=1
// Test 4: Two Separate Triangles
n=6, values={5,3,8, 2,9,1}, edges={(1,2),(2,3),(3,1), (4,5),(5,6),(6,4)}
// Comp1: {1,2,3} min=3, Comp2: {4,5,6} min=1, Sum=4
Union-Find (Disjoint Set Union) Alternative
เหมาะสำหรับ Dynamic Connectivity (Edge เพิ่ม/ลบบ่อย)
class DSU {
vector parent, minVal;
public:
DSU(int n, vector& values) : parent(n+1), minVal(n+1) {
for (int i = 1; i <= n; i++) {
parent[i] = i;
minVal[i] = values[i];
}
}
int find(int x) {
return parent[x] == x ? x : parent[x] = find(parent[x]);
}
void unite(int a, int b) {
a = find(a); b = find(b);
if (a != b) {
parent[b] = a;
minVal[a] = min(minVal[a], minVal[b]);
}
}
long long getSum() {
long long sum = 0;
for (int i = 1; i < parent.size(); i++) {
if (parent[i] == i) sum += minVal[i];
}
return sum;
}
};
ข้อควรระวัง
- Indexing: โจทย์มักใช้ 1-indexed (Node 1..N) แต่อาร์เรย์ C++ ใช้ 0-indexed
- Stack Overflow: DFS Recursive อาจล้มถ้า Component สูงมาก → ใช้ BFS หรือ Iterative DFS
- Multiple Edges/Self-loops: ไม่ส่งผลต่อ Minimum แต่ควร Handle ให้ถูกต้อง
- Large Values: ใช้ long long สำหรับ Sum