Traveling Salesman Problem (TSP) เป็นปัญหา optimization หาเส้นทางสั้นที่สุดที่ผ่านทุกเมืองครั้งละครั้งและกลับมาที่เริ่มต้น Nearest Neighbour เป็น heuristic แบบ greedy ให้คำตอบประมาณการรวดเร็ว
อัลกอริทึม Nearest Neighbour
- เริ่มจากเมืองใดเมืองหนึ่ง
- หาเมืองที่ใกล้ที่สุดที่ยังไม่ได้ไป
- ไปที่เมืองนั้น ทำซ้ำจนครบทุกเมือง
- กลับไปเมืองเริ่มต้น
Complexity: O(n²) ให้คำตอบไม่เกิน 2× optimal (สำหรับ metric TSP)
ตัวอย่างโค้ด (ปรับปรุงจากต้นฉบับ)
#include <iostream>
#include <vector>
#include <limits>
#include <algorithm>
using namespace std;
struct TSPResult {
vector<int> path;
double totalDistance;
};
class TSPSolver {
vector<vector<double>> distMatrix;
int n;
public:
TSPSolver(const vector<vector<double>>& matrix)
: distMatrix(matrix), n(matrix.size()) {}
TSPResult nearestNeighbour(int start = 0) {
vector<bool> visited(n, false);
vector<int> path;
path.reserve(n + 1);
int current = start;
path.push_back(current);
visited[current] = true;
double totalDist = 0.0;
// หา nearest neighbor ซ้ำ n-1 ครั้ง
for (int step = 1; step < n; ++step) {
int next = -1;
double minDist = numeric_limits<double>::max();
for (int i = 0; i < n; ++i) {
if (!visited[i] && distMatrix[current][i] < minDist) {
minDist = distMatrix[current][i];
next = i;
}
}
if (next == -1) break; // ไม่มีทางไปต่อ (disconnected)
path.push_back(next);
visited[next] = true;
totalDist += minDist;
current = next;
}
// กลับไปจุดเริ่มต้น
totalDist += distMatrix[current][start];
path.push_back(start);
return {path, totalDist};
}
// ลองเริ่มจากทุกเมือง หาค่าที่ดีที่สุด
TSPResult bestNearestNeighbour() {
TSPResult best;
best.totalDistance = numeric_limits<double>::max();
for (int start = 0; start < n; ++start) {
TSPResult result = nearestNeighbour(start);
if (result.totalDistance < best.totalDistance) {
best = result;
}
}
return best;
}
};
int main() {
// Distance matrix (symmetric)
vector<vector<double>> dist = {
{0, 10, 15, 20},
{10, 0, 35, 25},
{15, 35, 0, 30},
{20, 25, 30, 0}
};
TSPSolver solver(dist);
// เริ่มจากเมือง 0
auto result = solver.nearestNeighbour(0);
cout << "Path: ";
for (int city : result.path) {
cout << city << " ";
}
cout << "\nTotal Distance: " << result.totalDistance << endl;
// หาค่าที่ดีที่สุดจากทุกจุดเริ่มต้น
auto best = solver.bestNearestNeighbour();
cout << "\nBest start city: " << best.path[0] << endl;
cout << "Best Distance: " << best.totalDistance << endl;
return 0;
}
ผลลัพธ์
Path: 0 1 3 2 0 Total Distance: 80 Best start city: 0 Best Distance: 80
การปรับปรุง: 2-Opt Local Search
Nearest Neighbour ให้คำตอบเร็วแต่อาจไม่ดีพอ ใช้ 2-Opt ปรับปรุง:
void twoOpt(vector<int>& path, const vector<vector<double>>>> dist) {
bool improved = true;
while (improved) {
improved = false;
for (int i = 1; i < path.size() - 2; ++i) {
for (int k = i + 1; k < path.size() - 1; ++k) {
double current = dist[path[i-1]][path[i]] + dist[path[k]][path[k+1]];
double swapped = dist[path[i-1]][path[k]] + dist[path[i]][path[k+1]];
if (swapped < current) {
reverse(path.begin() + i, path.begin() + k + 1);
improved = true;
}
}
}
}
}
ข้อจำกัดของ Nearest Neighbour
- ไม่ guarantee optimal solution
- ผลลัพธ์ขึ้นกับ starting city
- ไม่คำนึงถึง global structure
อัลกอริทึม TSP อื่นๆ
| Algorithm | Type | Complexity | Quality |
|---|---|---|---|
| Brute Force | Exact | O(n!) | Optimal |
| Held-Karp (DP) | Exact | O(n²2ⁿ) | Optimal |
| Branch & Bound | Exact | Exponential | Optimal |
| Nearest Neighbour | Heuristic | O(n²) | ~25% over optimal |
| Christofides | Approximation | O(n³) | ≤ 1.5× optimal |
| Genetic Algorithm | Metaheuristic | Tunable | Good |
| Ant Colony | Metaheuristic | Tunable | Good |