唐朝天宝十四年,长安城一片繁华景象。唐玄宗对杨贵妃宠爱至极,听说岭南的荔枝鲜美无比,便想要在贵妃生日(六月初一)那天,让她吃上刚从枝头摘下的新鲜荔枝。
要知道,在那个交通靠走,通讯靠吼的古代,这基本个不可能的任务!荔枝离开树枝,三天就变色变味。岭南到长安,足足五千里,山高路远。大臣们都知道这是个烫手山芋,谁接谁倒霉。倒霉蛋叫李善德,一个在长安混了二十多年、刚借钱买了小房子的九品芝麻官。他被同僚算计,稀里糊涂接下了这个"荔枝使"的差事。这哪是美差?分明是催命符!他吓得差点直接准备后事。但李善德没放弃。在朋友鼓励下,他抱着最后一丝希望,拼了命赶往岭南。在那里,他遇到了精明的胡商苏谅和种荔枝的姑娘阿僮。李善德发挥自己精于计算的长处,疯狂实验保鲜方法,设计严密的运输路线和接力方案,动用了驿站系统、快马、骑手,甚至耗费巨资购买冰块。为了这两坛小小的荔枝,沿途累死了不知多少匹马,跑垮了多少健壮的骑手,耗尽了地方多少财力物力。李善德夹在皇命和残酷现实之间,到处求人、受气,甚至得罪了朋友。
终于在贵妃生日当天,一骑烟尘冲入长安城,带来了勉强还算新鲜的荔枝。贵妃笑了,李善德的"任务"完成了。但亲眼目睹这巨大代价的李善德,内心无法平静。这奢靡的"一骑红尘妃子笑"背后,是无数普通人的血汗甚至生命。他最终选择了良知,代价是被流放岭南。讽刺的是,第二年安史之乱爆发,长安沦陷,远离权力中心的李善德反而躲过了战火。
这个浪漫而又惊心动魄的故事,正是我们这次路径优化项目的灵感来源。试想一下,如果我们用现代的算法和可视化技术,是否能在当年那条"荔枝道"上,找出一条真正意义上的最优路径?
城市图建模
从深圳出发,送抵西安,找出一条时间或费用最优的现代运输路线。 根据提供的数据,我们构建了一张简化的城市图结构,每条道路都标注了运输数据,括号中的数字代表运输时间(单位:小时),我们可以将这张图理解为现代版"荔枝驿路"的抽象表达。每一段线路,不再是骑马与驿卒的奔波,而是运输车、物流网与算法智慧的协同决策。
arduino
city_graph = {
'深圳': {'广州': 1.5, '东莞': 1.0},
'广州': {'深圳': 1.5, '韶关': 2.5, '长沙': 5.5},
'东莞': {'深圳': 1.0, '惠州': 1.2},
'惠州': {'东莞': 1.2, '武汉': 8.0},
'韶关': {'广州': 2.5, '长沙': 4.0},
'长沙': {'韶关': 4.0, '武汉': 3.0, '郑州': 8.0},
'武汉': {'惠州': 8.0, '长沙': 3.0, '郑州': 4.5, '西安': 10.0},
'郑州': {'长沙': 8.0, '武汉': 4.5, '洛阳': 2.0},
'洛阳': {'郑州': 2.0, '西安': 5.0},
'西安': {'武汉': 10.0, '洛阳': 5.0}
}
算法选择
在如何走得更快这个问题上,古代靠人力和马匹,我们则靠算法。我们引入了三种现代路径搜索算法:
- Dijkstra算法: 找出从起点到终点的最短时间路径,适用于只考虑时间最优的场景。
- A Star 算法: 使用启发函数(如地理坐标距离)引导搜索,速度更快,方向更明确,就像驿使心中早已有图。
- 双目标加权算法: 同时考虑时间与费用,根据用户设定的权重系数,灵活决定是要快,还是要省,亦或二者兼顾。

多目标系统
在系统设计上,我们特别实现了一个灵活的双目标决策系统:
- 时间权重(如0.7) :代表任务对速度的敏感程度
- 费用权重(如0.3) :代表对成本的重视程度
- 二者总和固定为1,用户可拖动滑块动态调整,系统即时计算

比如在 **"荔枝必须三日内送达" **这种高度时效场景下,用户可能将时间权重拉高至 0.9;而在日常物流配送中,则可以更侧重费用优化。每一次调整,系统都会自动重新计算所有可能路径,并在地图上直观展示结果。
可视化界面
为了让技术结果更具直观性,我们用 HTML + JavaScript 构建了交互式路径地图,用户点击起点与终点,拖动权重滑块,点击"运行算法",即可实时看到哪一条路线最合适,不论是为了"贵妃一笑"还是"成本最省"。主要包括:
- SVG 城市图谱:展示所有节点与路径连接
- 动态路径高亮:最优路线将沿图路径流动,犹如"荔枝专列"横穿中国
- 节点悬停提示:显示每个城市的运输详情
- 路径动画:模拟荔枝由南向北奔袭的过程

路线分析报告
系统在路径计算完成后,还会生成一份详细分析报告,包括:

现代技术,古人心愿
当我们借助 Dijkstra、A* 与加权算法追寻一条条最优路径时,仿佛也参与了一场与古人的运输任务。不同的是,古人靠的是驿站与人力,而我们,靠的是算力与数据。"长安的荔枝",不再是千里奔袭下的奢侈与浪漫,而是数字化时代路径优化的现实案例。
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能路径规划系统</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
font-size: 1.1em;
opacity: 0.9;
}
.main-content {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 30px;
padding: 30px;
}
.control-panel {
background: #f8f9fa;
padding: 25px;
border-radius: 10px;
height: fit-content;
}
.section {
margin-bottom: 25px;
}
.section h3 {
color: #333;
margin-bottom: 15px;
font-size: 1.2em;
border-bottom: 2px solid #4facfe;
padding-bottom: 5px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
select, input[type="range"], button {
width: 100%;
padding: 10px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 14px;
}
select:focus, input:focus {
outline: none;
border-color: #4facfe;
}
.weight-control {
display: flex;
align-items: center;
gap: 10px;
}
.weight-control input {
flex: 1;
}
.weight-value {
min-width: 40px;
text-align: center;
font-weight: bold;
color: #4facfe;
}
button {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
border: none;
cursor: pointer;
font-weight: bold;
transition: transform 0.2s;
}
button:hover {
transform: translateY(-2px);
}
.algorithm-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.map-container {
background: white;
border-radius: 10px;
border: 2px solid #eee;
position: relative;
height: 600px;
overflow: hidden;
}
.map-svg {
width: 100%;
height: 100%;
}
.city-node {
fill: #4facfe;
stroke: white;
stroke-width: 3;
cursor: pointer;
transition: all 0.3s;
}
.city-node:hover {
fill: #ff6b6b;
transform: scale(1.2);
}
.city-label {
font-size: 12px;
font-weight: bold;
fill: #333;
text-anchor: middle;
pointer-events: none;
}
.edge {
stroke: #ccc;
stroke-width: 2;
fill: none;
}
.edge-label {
font-size: 10px;
fill: #666;
text-anchor: middle;
}
.path-edge {
stroke: #ff6b6b;
stroke-width: 4;
animation: pathAnimation 2s ease-in-out;
}
@keyframes pathAnimation {
0% { stroke-dasharray: 1000; stroke-dashoffset: 1000; }
100% { stroke-dasharray: 1000; stroke-dashoffset: 0; }
}
.results {
margin-top: 20px;
padding: 20px;
background: #e8f5e8;
border-radius: 10px;
border-left: 5px solid #28a745;
}
.results h4 {
color: #28a745;
margin-bottom: 10px;
}
.path-info {
margin-bottom: 15px;
}
.path-steps {
background: white;
padding: 15px;
border-radius: 5px;
margin-top: 10px;
}
.step {
display: flex;
justify-content: space-between;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.step:last-child {
border-bottom: none;
}
.comparison-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
.comparison-table th,
.comparison-table td {
padding: 10px;
text-align: center;
border: 1px solid #ddd;
}
.comparison-table th {
background: #4facfe;
color: white;
}
.best-result {
background: #d4edda !important;
font-weight: bold;
}
@media (max-width: 1024px) {
.main-content {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<header class="header">
<h1>🗺️ 智能路径规划系统</h1>
<p>多算法路径优化 | 双目标决策 | 可视化展示</p>
</header>
<div class="main-content">
<div class="control-panel">
<div class="section">
<h3>🎯 路径设置</h3>
<div class="form-group">
<label for="startCity">起始城市:</label>
<select id="startCity">
<option value="深圳" selected>深圳</option>
<option value="广州">广州</option>
<option value="东莞">东莞</option>
<option value="惠州">惠州</option>
<option value="韶关">韶关</option>
<option value="长沙">长沙</option>
<option value="武汉">武汉</option>
<option value="郑州">郑州</option>
<option value="洛阳">洛阳</option>
<option value="西安">西安</option>
</select>
</div>
<div class="form-group">
<label for="endCity">目标城市:</label>
<select id="endCity">
<option value="深圳">深圳</option>
<option value="广州">广州</option>
<option value="东莞">东莞</option>
<option value="惠州">惠州</option>
<option value="韶关">韶关</option>
<option value="长沙">长沙</option>
<option value="武汉">武汉</option>
<option value="郑州">郑州</option>
<option value="洛阳">洛阳</option>
<option value="西安" selected>西安</option>
</select>
</div>
</div>
<div class="section">
<h3>⚖️ 优化权重</h3>
<div class="form-group">
<label>时间权重: <span id="timeWeightValue">0.5</span></label>
<div class="weight-control">
<input type="range" id="timeWeight" min="0" max="1" step="0.1" value="0.5">
</div>
</div>
<div class="form-group">
<label>费用权重: <span id="costWeightValue">0.5</span></label>
<div class="weight-control">
<input type="range" id="costWeight" min="0" max="1" step="0.1" value="0.5">
</div>
</div>
</div>
<div class="section">
<h3>🔍 算法选择</h3>
<div class="algorithm-buttons">
<button onclick="runAlgorithm('dijkstra')">Dijkstra</button>
<button onclick="runAlgorithm('astar')">A* 算法</button>
<button onclick="runAlgorithm('weighted')">加权优化</button>
<button onclick="compareAlgorithms()">算法对比</button>
</div>
</div>
<div id="results" class="results" style="display: none;">
<h4>📊 计算结果</h4>
<div id="resultContent"></div>
</div>
</div>
<div class="map-container">
<svg class="map-svg" id="mapSvg" viewBox="0 0 800 600">
<!-- 地图将由JavaScript动态生成 -->
</svg>
</div>
</div>
</div>
<script>
// 城市数据:包含坐标、时间和费用信息
const cityData = {
'深圳': { x: 150, y: 500, connections: { '广州': { time: 1.5, cost: 120 }, '东莞': { time: 1.0, cost: 80 } } },
'广州': { x: 100, y: 450, connections: { '深圳': { time: 1.5, cost: 120 }, '韶关': { time: 2.5, cost: 200 }, '长沙': { time: 5.5, cost: 450 } } },
'东莞': { x: 200, y: 480, connections: { '深圳': { time: 1.0, cost: 80 }, '惠州': { time: 1.2, cost: 100 } } },
'惠州': { x: 250, y: 450, connections: { '东莞': { time: 1.2, cost: 100 }, '武汉': { time: 8.0, cost: 600 } } },
'韶关': { x: 150, y: 350, connections: { '广州': { time: 2.5, cost: 200 }, '长沙': { time: 4.0, cost: 320 } } },
'长沙': { x: 300, y: 300, connections: { '韶关': { time: 4.0, cost: 320 }, '武汉': { time: 3.0, cost: 240 }, '郑州': { time: 8.0, cost: 640 } } },
'武汉': { x: 400, y: 250, connections: { '惠州': { time: 8.0, cost: 600 }, '长沙': { time: 3.0, cost: 240 }, '郑州': { time: 4.5, cost: 360 }, '西安': { time: 10.0, cost: 800 } } },
'郑州': { x: 500, y: 200, connections: { '长沙': { time: 8.0, cost: 640 }, '武汉': { time: 4.5, cost: 360 }, '洛阳': { time: 2.0, cost: 160 } } },
'洛阳': { x: 550, y: 150, connections: { '郑州': { time: 2.0, cost: 160 }, '西安': { time: 5.0, cost: 400 } } },
'西安': { x: 600, y: 100, connections: { '武汉': { time: 10.0, cost: 800 }, '洛阳': { time: 5.0, cost: 400 } } }
};
// 初始化地图
function initMap() {
const svg = document.getElementById('mapSvg');
svg.innerHTML = '';
// 绘制连接线
Object.keys(cityData).forEach(city => {
const cityInfo = cityData[city];
Object.keys(cityInfo.connections).forEach(targetCity => {
const targetInfo = cityData[targetCity];
const connection = cityInfo.connections[targetCity];
// 绘制连接线
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', cityInfo.x);
line.setAttribute('y1', cityInfo.y);
line.setAttribute('x2', targetInfo.x);
line.setAttribute('y2', targetInfo.y);
line.setAttribute('class', 'edge');
line.setAttribute('id', `edge-${city}-${targetCity}`);
svg.appendChild(line);
// 添加连接信息标签
const midX = (cityInfo.x + targetInfo.x) / 2;
const midY = (cityInfo.y + targetInfo.y) / 2;
const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
label.setAttribute('x', midX);
label.setAttribute('y', midY - 5);
label.setAttribute('class', 'edge-label');
label.textContent = `${connection.time}h/${connection.cost}¥`;
svg.appendChild(label);
});
});
// 绘制城市节点
Object.keys(cityData).forEach(city => {
const cityInfo = cityData[city];
// 城市圆圈
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', cityInfo.x);
circle.setAttribute('cy', cityInfo.y);
circle.setAttribute('r', 15);
circle.setAttribute('class', 'city-node');
circle.setAttribute('id', `node-${city}`);
svg.appendChild(circle);
// 城市标签
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', cityInfo.x);
text.setAttribute('y', cityInfo.y + 25);
text.setAttribute('class', 'city-label');
text.textContent = city;
svg.appendChild(text);
});
}
// Dijkstra算法实现
function dijkstra(graph, start, end, weightFunc) {
const distances = {};
const previous = {};
const visited = new Set();
const queue = [];
// 初始化距离
Object.keys(graph).forEach(node => {
distances[node] = node === start ? 0 : Infinity;
queue.push({ node, distance: distances[node] });
});
while (queue.length > 0) {
// 找到最小距离的节点
queue.sort((a, b) => a.distance - b.distance);
const current = queue.shift();
if (visited.has(current.node) || current.distance === Infinity) continue;
if (current.node === end) break;
visited.add(current.node);
// 更新邻居节点距离
Object.keys(graph[current.node].connections).forEach(neighbor => {
if (!visited.has(neighbor)) {
const connection = graph[current.node].connections[neighbor];
const weight = weightFunc(connection);
const newDistance = distances[current.node] + weight;
if (newDistance < distances[neighbor]) {
distances[neighbor] = newDistance;
previous[neighbor] = current.node;
// 更新队列中的距离
const neighborInQueue = queue.find(item => item.node === neighbor);
if (neighborInQueue) {
neighborInQueue.distance = newDistance;
}
}
}
});
}
// 重构路径
const path = [];
let current = end;
while (current !== undefined) {
path.unshift(current);
current = previous[current];
}
return { path, totalCost: distances[end] };
}
// A*算法实现
function astar(graph, start, end, weightFunc) {
const openSet = [{ node: start, g: 0, f: 0 }];
const closedSet = new Set();
const gScore = { [start]: 0 };
const fScore = { [start]: heuristic(start, end) };
const previous = {};
while (openSet.length > 0) {
openSet.sort((a, b) => a.f - b.f);
const current = openSet.shift();
if (current.node === end) {
const path = [];
let node = end;
while (node !== undefined) {
path.unshift(node);
node = previous[node];
}
return { path, totalCost: gScore[end] };
}
closedSet.add(current.node);
Object.keys(graph[current.node].connections).forEach(neighbor => {
if (closedSet.has(neighbor)) return;
const connection = graph[current.node].connections[neighbor];
const tentativeG = gScore[current.node] + weightFunc(connection);
if (!gScore.hasOwnProperty(neighbor) || tentativeG < gScore[neighbor]) {
previous[neighbor] = current.node;
gScore[neighbor] = tentativeG;
fScore[neighbor] = gScore[neighbor] + heuristic(neighbor, end);
if (!openSet.find(item => item.node === neighbor)) {
openSet.push({
node: neighbor,
g: gScore[neighbor],
f: fScore[neighbor]
});
}
}
});
}
return { path: [], totalCost: Infinity };
}
// 启发式函数(欧几里得距离)
function heuristic(city1, city2) {
const pos1 = cityData[city1];
const pos2 = cityData[city2];
return Math.sqrt(Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2)) / 100;
}
// 权重函数
function getWeightFunction() {
const timeWeight = parseFloat(document.getElementById('timeWeight').value);
const costWeight = parseFloat(document.getElementById('costWeight').value);
return (connection) => {
return timeWeight * connection.time + costWeight * (connection.cost / 100);
};
}
// 运行指定算法
function runAlgorithm(algorithm) {
const startCity = document.getElementById('startCity').value;
const endCity = document.getElementById('endCity').value;
if (startCity === endCity) {
alert('起始城市和目标城市不能相同!');
return;
}
const weightFunc = getWeightFunction();
let result;
switch (algorithm) {
case 'dijkstra':
result = dijkstra(cityData, startCity, endCity, weightFunc);
break;
case 'astar':
result = astar(cityData, startCity, endCity, weightFunc);
break;
case 'weighted':
result = dijkstra(cityData, startCity, endCity, weightFunc);
break;
}
displayResult(result, algorithm);
highlightPath(result.path);
}
// 算法对比
function compareAlgorithms() {
const startCity = document.getElementById('startCity').value;
const endCity = document.getElementById('endCity').value;
if (startCity === endCity) {
alert('起始城市和目标城市不能相同!');
return;
}
const timeWeightFunc = (conn) => conn.time;
const costWeightFunc = (conn) => conn.cost / 100;
const weightedFunc = getWeightFunction();
const results = {
'最短时间(Dijkstra)': dijkstra(cityData, startCity, endCity, timeWeightFunc),
'最低费用(Dijkstra)': dijkstra(cityData, startCity, endCity, costWeightFunc),
'加权优化(Dijkstra)': dijkstra(cityData, startCity, endCity, weightedFunc),
'A*算法': astar(cityData, startCity, endCity, weightedFunc)
};
displayComparison(results);
}
// 显示单个结果
function displayResult(result, algorithm) {
if (result.path.length === 0) {
document.getElementById('resultContent').innerHTML = '<p>无法找到路径!</p>';
document.getElementById('results').style.display = 'block';
return;
}
const totalTime = calculateTotalTime(result.path);
const totalCost = calculateTotalCost(result.path);
let html = `
<div class="path-info">
<strong>算法:</strong> ${getAlgorithmName(algorithm)}<br>
<strong>路径:</strong> ${result.path.join(' → ')}<br>
<strong>总时间:</strong> ${totalTime.toFixed(1)} 小时<br>
<strong>总费用:</strong> ¥${totalCost}<br>
<strong>综合评分:</strong> ${result.totalCost.toFixed(2)}
</div>
<div class="path-steps">
<h5>详细路径:</h5>
`;
for (let i = 0; i < result.path.length - 1; i++) {
const from = result.path[i];
const to = result.path[i + 1];
const connection = cityData[from].connections[to];
html += `
<div class="step">
<span>${from} → ${to}</span>
<span>${connection.time}h / ¥${connection.cost}</span>
</div>
`;
}
html += '</div>';
document.getElementById('resultContent').innerHTML = html;
document.getElementById('results').style.display = 'block';
}
// 显示算法对比结果
function displayComparison(results) {
let html = '<h5>算法性能对比:</h5>';
html += `
<table class="comparison-table">
<tr>
<th>算法</th>
<th>路径</th>
<th>总时间(h)</th>
<th>总费用(¥)</th>
<th>综合评分</th>
</tr>
`;
let bestTime = Infinity, bestCost = Infinity, bestScore = Infinity;
const processedResults = {};
// 计算各项指标
Object.keys(results).forEach(algorithmName => {
const result = results[algorithmName];
if (result.path.length > 0) {
const totalTime = calculateTotalTime(result.path);
const totalCost = calculateTotalCost(result.path);
processedResults[algorithmName] = {
...result,
totalTime,
totalCost
};
bestTime = Math.min(bestTime, totalTime);
bestCost = Math.min(bestCost, totalCost);
bestScore = Math.min(bestScore, result.totalCost);
}
});
// 生成表格行
Object.keys(processedResults).forEach(algorithmName => {
const data = processedResults[algorithmName];
const isTimeWinner = data.totalTime === bestTime;
const isCostWinner = data.totalCost === bestCost;
const isScoreWinner = data.totalCost === bestScore;
html += `
<tr>
<td>${algorithmName}</td>
<td>${data.path.join(' → ')}</td>
<td class="${isTimeWinner ? 'best-result' : ''}">${data.totalTime.toFixed(1)}</td>
<td class="${isCostWinner ? 'best-result' : ''}">${data.totalCost}</td>
<td class="${isScoreWinner ? 'best-result' : ''}">${data.totalCost.toFixed(2)}</td>
</tr>
`;
});
html += '</table>';
// 高亮最优路径
const bestResult = Object.values(processedResults).find(r => r.totalCost === bestScore);
if (bestResult) {
highlightPath(bestResult.path);
}
document.getElementById('resultContent').innerHTML = html;
document.getElementById('results').style.display = 'block';
}
// 高亮显示路径
function highlightPath(path) {
// 清除之前的高亮
document.querySelectorAll('.path-edge').forEach(edge => {
edge.classList.remove('path-edge');
});
// 高亮新路径
for (let i = 0; i < path.length - 1; i++) {
const from = path[i];
const to = path[i + 1];
const edge = document.getElementById(`edge-${from}-${to}`) ||
document.getElementById(`edge-${to}-${from}`);
if (edge) {
edge.classList.add('path-edge');
}
}
}
// 辅助函数
function calculateTotalTime(path) {
let total = 0;
for (let i = 0; i < path.length - 1; i++) {
total += cityData[path[i]].connections[path[i + 1]].time;
}
return total;
}
function calculateTotalCost(path) {
let total = 0;
for (let i = 0; i < path.length - 1; i++) {
total += cityData[path[i]].connections[path[i + 1]].cost;
}
return total;
}
function getAlgorithmName(algorithm) {
const names = {
'dijkstra': 'Dijkstra算法',
'astar': 'A*算法',
'weighted': '加权优化算法'
};
return names[algorithm] || algorithm;
}
// 权重滑块事件处理
document.getElementById('timeWeight').addEventListener('input', function() {
const value = this.value;
document.getElementById('timeWeightValue').textContent = value;
document.getElementById('costWeight').value = (1 - parseFloat(value)).toFixed(1);
document.getElementById('costWeightValue').textContent = (1 - parseFloat(value)).toFixed(1);
});
document.getElementById('costWeight').addEventListener('input', function() {
const value = this.value;
document.getElementById('costWeightValue').textContent = value;
document.getElementById('timeWeight').value = (1 - parseFloat(value)).toFixed(1);
document.getElementById('timeWeightValue').textContent = (1 - parseFloat(value)).toFixed(1);
});
// 页面加载完成后初始化
window.addEventListener('load', function() {
initMap();
});
</script>
</body>
</html>