1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
| /**
* 贪心算法TSP求解器
* 最近邻居法快速近似解
*/
public class GreedyTSPSolver {
/**
* 贪心算法求解结果类
*/
public static class GreedyResult {
public double totalDistance;
public List<Integer> path;
public List<String> stepLog;
public GreedyResult(double totalDistance, List<Integer> path, List<String> stepLog) {
this.totalDistance = totalDistance;
this.path = path;
this.stepLog = stepLog;
}
}
/**
* 贪心算法:最近邻居法
* 每次选择距离当前位置最近的未访问节点
*
* @param distanceMatrix 距离矩阵
* @param start 起始节点(默认为0,即餐厅)
* @return GreedyResult包含总距离、路径和执行日志
*/
public static GreedyResult greedyNearestNeighbor(double[][] distanceMatrix, int start) {
int n = distanceMatrix.length;
boolean[] visited = new boolean[n];
List<Integer> path = new ArrayList<>();
List<String> stepLog = new ArrayList<>();
String[] nodeNames = {"餐厅", "客户A", "客户B", "客户C", "客户D",
"客户E", "客户F", "客户G", "客户H"};
path.add(start);
visited[start] = true;
double totalDistance = 0.0;
int current = start;
System.out.println("🏪 从餐厅出发,开始贪心选择...");
stepLog.add("🏪 从餐厅出发,开始贪心选择...");
// 贪心选择最近的未访问节点
for (int step = 0; step < n - 1; step++) {
double minDist = Double.POSITIVE_INFINITY;
int nextNode = -1;
// 寻找最近的未访问节点
for (int j = 0; j < n; j++) {
if (!visited[j] && distanceMatrix[current][j] < minDist) {
minDist = distanceMatrix[current][j];
nextNode = j;
}
}
visited[nextNode] = true;
path.add(nextNode);
totalDistance += minDist;
// 记录每步选择
String stepInfo = String.format("步骤%d: %s → %s (%.1fkm)",
step + 1, nodeNames[current], nodeNames[nextNode], minDist);
System.out.println(stepInfo);
stepLog.add(stepInfo);
current = nextNode;
}
// 回到起点
double returnDist = distanceMatrix[current][start];
totalDistance += returnDist;
path.add(start);
String finalStep = String.format("最后: %s → 餐厅 (%.1fkm)", nodeNames[current], returnDist);
System.out.println(finalStep);
stepLog.add(finalStep);
String summary = String.format("✅ 贪心算法完成,总距离: %.1fkm", totalDistance);
System.out.println(summary);
stepLog.add(summary);
return new GreedyResult(totalDistance, path, stepLog);
}
/**
* 算法复杂度分析
*/
public static void analyzeAlgorithmComplexity() {
System.out.println("\n📊 算法复杂度对比分析:");
System.out.println("-".repeat(85));
System.out.printf("%-12s %-15s %-15s %-12s %-15s%n",
"算法名称", "时间复杂度", "空间复杂度", "适用规模", "解的质量");
System.out.println("-".repeat(85));
// 算法复杂度数据
Object[][] complexityData = {
{"暴力枚举法", "O(n!)", "O(n)", "n ≤ 10", "100%最优解"},
{"动态规划法", "O(n²×2ⁿ)", "O(n×2ⁿ)", "n ≤ 20", "100%最优解"},
{"贪心算法", "O(n²)", "O(n)", "n ≤ 1000+", "70-90%近似解"},
{"遗传算法", "O(代数×种群×n²)", "O(种群×n)", "n ≤ 10000+", "85-95%近似解"}
};
for (Object[] row : complexityData) {
System.out.printf("%-12s %-15s %-15s %-12s %-15s%n",
row[0], row[1], row[2], row[3], row[4]);
}
}
/**
* 主函数 - 演示贪心算法执行过程
*/
public static void main(String[] args) {
// 距离矩阵(与上面动态规划使用相同数据)
double[][] distanceMatrix = {
{0.0, 2.1, 1.8, 3.2, 2.7, 4.1, 1.9, 3.5, 2.4},
{2.1, 0.0, 1.5, 2.8, 3.1, 3.9, 2.7, 4.2, 1.8},
{1.8, 1.5, 0.0, 2.4, 2.2, 3.6, 1.4, 3.8, 2.1},
{3.2, 2.8, 2.4, 0.0, 1.6, 2.1, 3.1, 1.9, 3.7},
{2.7, 3.1, 2.2, 1.6, 0.0, 2.8, 2.9, 2.3, 3.2},
{4.1, 3.9, 3.6, 2.1, 2.8, 0.0, 4.3, 1.2, 4.8},
{1.9, 2.7, 1.4, 3.1, 2.9, 4.3, 0.0, 4.1, 2.6},
{3.5, 4.2, 3.8, 1.9, 2.3, 1.2, 4.1, 0.0, 4.5},
{2.4, 1.8, 2.1, 3.7, 3.2, 4.8, 2.6, 4.5, 0.0}
};
System.out.println("🎯 执行贪心算法(最近邻居法):");
// 执行贪心算法并显示详细过程
long startTime = System.currentTimeMillis();
GreedyResult greedyResult = greedyNearestNeighbor(distanceMatrix, 0);
long endTime = System.currentTimeMillis();
System.out.println("\n📈 贪心算法性能统计:");
System.out.println("⏱️ 执行时间: " + (endTime - startTime) + "ms");
System.out.printf("🚩 贪心解路径长度: %.1fkm%n", greedyResult.totalDistance);
// 进行算法复杂度分析
analyzeAlgorithmComplexity();
// 与最优解对比(假设已知最优解为18.7km)
double optimalDistance = 18.7;
double approximationRatio = (greedyResult.totalDistance / optimalDistance);
double errorPercentage = (approximationRatio - 1) * 100;
System.out.println("\n🔍 算法质量分析:");
System.out.printf("🎯 已知最优解: %.1fkm%n", optimalDistance);
System.out.printf("⚡ 贪心算法解: %.1fkm%n", greedyResult.totalDistance);
System.out.printf("📊 近似比率: %.2f%n", approximationRatio);
System.out.printf("📉 误差百分比: %.1f%%%n", errorPercentage);
// 输出执行日志
System.out.println("\n📋 详细执行日志:");
for (String log : greedyResult.stepLog) {
System.out.println(log);
}
}
}
|