返回列表
数学

将军饮马

上传时间:2026-04-09 10:59 · 作者:ytry1983

解题过程与思路预览 请仅渲染可信 HTML
最短距离:将军饮马问题演示

最短距离:将军饮马 (第10题)

利用“轴对称”原理求解线段之和最小值

河岸 CD C D 地点 A (牧童) AC = 400m 地点 B (家) BD = 200m

📝 数学计算过程

1. **对称性**:作 $A$ 关于河岸的对称点 $A'$,则 $AC = A'C = 400\text{m}$。

2. **最短路径**:连接 $A'B$,根据“两点之间线段最短”,线段 $A'B$ 的长度即为最短路程。

3. **勾股定理**:构造直角三角形,直角边长分别为:

  • 水平方向距离 = $CD = 800\text{m}$
  • 垂直方向距离 = $AC + BD = 400 + 200 = 600\text{m}$

4. **结果**:最短路程 = $\sqrt{800^2 + 600^2} = 1000\text{m}$。

💡 饮水点 $P$ 的位置

通过相似三角形推导,饮水点 $P$ 距离 $C$ 点的距离为:
$800 \times \frac{400}{400+200} = 800 \times \frac{2}{3} \approx 533.3\text{米}$。

查看解析页源码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>最短距离:将军饮马问题演示</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- 引入 MathJax 配置 -->
    <script>
        window.MathJax = {
            tex: {
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                displayMath: [['$$', '$$'], ['\\[', '\\]']]
            },
            options: {
                skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre']
            },
            startup: {
                ready: () => {
                    MathJax.startup.defaultReady();
                    console.log('MathJax is ready');
                    // 初始渲染
                    window.renderMath();
                }
            }
        };
    </script>
    <!-- 引入 MathJax 渲染库 (v3) -->
    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
    <style>
        .step-transition {
            transition: all 0.5s ease-in-out;
        }
        @keyframes pulse-dot {
            0%, 100% { transform: scale(1); opacity: 1; }
            50% { transform: scale(1.3); opacity: 0.7; }
        }
        .animate-pulse-custom {
            animation: pulse-dot 2s infinite;
        }
        .math-font {
            font-family: 'Times New Roman', serif;
            font-style: italic;
        }
    </style>
</head>
<body class="bg-slate-50 min-h-screen font-sans p-4 md:p-8 flex flex-col items-center">

    <div class="max-w-4xl w-full bg-white rounded-2xl shadow-xl overflow-hidden border border-slate-200">
        <!-- Header -->
        <div class="bg-blue-600 p-6 text-white text-center">
            <h1 class="text-2xl font-bold text-white">最短距离:将军饮马 (第10题)</h1>
            <p class="mt-2 opacity-90 text-white">利用“轴对称”原理求解线段之和最小值</p>
        </div>

        <!-- Animation Area -->
        <div class="relative h-[600px] w-full bg-slate-50 border-y border-slate-200 overflow-hidden">
            <!-- 视图优化:y轴从-150开始,确保对称点可见;底部预留空间防止遮挡 -->
            <svg id="animation-svg" class="w-full h-full" viewBox="0 -150 800 750" preserveAspectRatio="xMidYMid meet">
                <!-- 河流背景 -->
                <rect x="0" y="150" width="800" height="40" fill="#e0f2fe" opacity="0.8" />
                <line x1="0" y1="150" x2="800" y2="150" stroke="#0ea5e9" stroke-width="2" />
                <text x="740" y="140" fill="#0ea5e9" class="text-sm font-bold italic">河岸 CD</text>
                
                <text x="100" y="140" class="font-bold fill-slate-600">C</text>
                <text x="700" y="140" class="font-bold fill-slate-600">D</text>

                <g id="points-static">
                    <!-- A点位置优化 -->
                    <circle cx="100" cy="390" r="6" fill="#ef4444" />
                    <text x="80" y="415" class="font-bold fill-slate-800">地点 A (牧童)</text>
                    <text x="110" y="380" class="text-[10px] fill-slate-400 italic">AC = 400m</text>
                    
                    <!-- B点位置优化 -->
                    <circle cx="580" cy="270" r="6" fill="#ef4444" />
                    <text x="590" y="285" class="font-bold fill-slate-800">地点 B (家)</text>
                    <text x="520" y="260" class="text-[10px] fill-slate-400 italic">BD = 200m</text>
                </g>

                <g id="dynamic-layers"></g>
            </svg>

            <!-- Overlay Info - 背景更透明,且设置 pointer-events-none 防止干扰点击 -->
            <div id="info-box" class="absolute bottom-4 left-6 right-6 bg-white/80 backdrop-blur-sm p-4 rounded-xl shadow-lg border border-blue-100 transition-opacity duration-300 pointer-events-none">
                <h3 id="step-title" class="text-lg font-bold text-blue-900"></h3>
                <p id="step-desc" class="text-slate-700 text-sm mt-1"></p>
            </div>
        </div>

        <!-- Controls -->
        <div class="p-6 flex justify-between items-center bg-slate-50">
            <button id="prev-btn" class="px-6 py-2 rounded-full border border-slate-300 text-slate-600 hover:bg-white transition-all active:scale-95 disabled:opacity-50">
                上一步
            </button>
            
            <div id="dot-indicators" class="flex gap-2"></div>

            <button id="next-btn" class="px-6 py-2 rounded-full bg-blue-600 text-white hover:bg-blue-700 transition-all shadow-lg shadow-blue-200 active:scale-95">
                下一步
            </button>
        </div>
    </div>

    <!-- Math Calculation Box -->
    <div id="math-box" class="mt-8 grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl w-full pb-12">
        <div class="bg-white p-6 rounded-xl shadow-sm border border-slate-200">
            <h4 class="font-bold text-blue-800 flex items-center gap-2">
                <span>📝</span> 数学计算过程
            </h4>
            <div class="text-sm text-slate-600 mt-2 space-y-2 leading-relaxed">
                <p>1. **对称性**:作 $A$ 关于河岸的对称点 $A'$,则 $AC = A'C = 400\text{m}$。</p>
                <p>2. **最短路径**:连接 $A'B$,根据“两点之间线段最短”,线段 $A'B$ 的长度即为最短路程。</p>
                <p>3. **勾股定理**:构造直角三角形,直角边长分别为:</p>
                <ul class="list-disc list-inside ml-4">
                    <li>水平方向距离 = $CD = 800\text{m}$</li>
                    <li>垂直方向距离 = $AC + BD = 400 + 200 = 600\text{m}$</li>
                </ul>
                <p>4. **结果**:最短路程 = $\sqrt{800^2 + 600^2} = 1000\text{m}$。</p>
            </div>
        </div>
        <div class="bg-white p-6 rounded-xl shadow-sm border border-slate-200">
            <h4 class="font-bold text-blue-800 flex items-center gap-2">
                <span>💡</span> 饮水点 $P$ 的位置
            </h4>
            <p class="text-sm text-slate-600 mt-2">
                通过相似三角形推导,饮水点 $P$ 距离 $C$ 点的距离为:<br>
                $800 \times \frac{400}{400+200} = 800 \times \frac{2}{3} \approx 533.3\text{米}$。
            </p>
        </div>
    </div>

    <script>
        // 定义全局渲染函数,包含安全检查
        window.renderMath = () => {
            if (window.MathJax && typeof MathJax.typesetPromise === 'function') {
                MathJax.typesetPromise([document.getElementById('info-box'), document.getElementById('math-box')]).catch((err) => console.log(err));
            } else if (window.MathJax && typeof MathJax.typeset === 'function') {
                MathJax.typeset([document.getElementById('info-box'), document.getElementById('math-box')]);
            }
        };

        const steps = [
            { title: "1. 初始场景", desc: "地点 $A$(牧童)和 $B$(家)在河岸 $CD$ 的同侧。需要找到岸上的一点 $P$ 使得 $AP+PB$ 最短。" },
            { title: "2. 作对称点 $A'$", desc: "以河岸为对称轴,作 $A$ 的对称点 $A'$。此时 $AC = A'C = 400\text{m}$。" },
            { title: "3. 连接 $A'B$", desc: "由于 $AP = A'P$,所以 $AP+PB = A'P+PB$。根据两点间线段最短,$A'B$ 即为所求路径。" },
            { title: "4. 确定饮水点 $P$", desc: "线段 $A'B$ 与河岸的交点即为最优饮水位置 $P$。" },
            { title: "5. 最终路径与计算", desc: "最短路程为 $A'B$ 的长度。构建直角三角形(底 $800$,高 $600$),斜边为 $\sqrt{800^2 + 600^2} = 1000$ 米。" }
        ];

        let currentStep = 0;
        const dynamicLayer = document.getElementById('dynamic-layers');
        const stepTitle = document.getElementById('step-title');
        const stepDesc = document.getElementById('step-desc');
        const prevBtn = document.getElementById('prev-btn');
        const nextBtn = document.getElementById('next-btn');
        const dotIndicators = document.getElementById('dot-indicators');

        steps.forEach((_, i) => {
            const dot = document.createElement('div');
            dot.className = `h-2 w-8 rounded-full transition-all ${i === 0 ? 'bg-blue-600 w-12' : 'bg-slate-300'}`;
            dotIndicators.appendChild(dot);
        });

        function updateUI() {
            stepTitle.textContent = steps[currentStep].title;
            stepDesc.textContent = steps[currentStep].desc;
            prevBtn.disabled = currentStep === 0;
            nextBtn.textContent = currentStep === steps.length - 1 ? "重新开始" : "下一步";

            Array.from(dotIndicators.children).forEach((dot, i) => {
                dot.className = `h-2 transition-all rounded-full ${i === currentStep ? 'bg-blue-600 w-12' : 'bg-slate-300 w-8'}`;
            });

            dynamicLayer.innerHTML = '';

            const riverY = 150;
            const pA = { x: 100, y: 390 }; 
            const pB = { x: 580, y: 270 };
            const pAPrime = { x: 100, y: 150 - 240 }; 

            if (currentStep >= 1) {
                createSVGElement('line', { x1: pA.x, y1: pA.y, x2: pAPrime.x, y2: pAPrime.y, stroke: '#94a3b8', 'stroke-width': 1.5, 'stroke-dasharray': '4' });
                createSVGElement('circle', { cx: pAPrime.x, cy: pAPrime.y, r: 6, fill: '#f59e0b', class: 'animate-pulse-custom' });
                createSVGElement('text', { x: 75, y: pAPrime.y - 15, class: 'fill-amber-600 font-bold', textContent: "A'" });
            }

            if (currentStep >= 2) {
                createSVGElement('line', { x1: pAPrime.x, y1: pAPrime.y, x2: pB.x, y2: pB.y, stroke: '#94a3b8', 'stroke-width': 2, 'stroke-dasharray': '8' });
            }

            if (currentStep >= 3) {
                const k = (pB.y - pAPrime.y) / (pB.x - pAPrime.x);
                const pX = (riverY - pAPrime.y) / k + pAPrime.x;
                createSVGElement('circle', { cx: pX, cy: riverY, r: 5, fill: '#10b981' });
                createSVGElement('text', { x: pX - 5, y: riverY - 15, class: 'fill-emerald-700 font-bold text-xs', textContent: 'P' });
            }

            if (currentStep >= 4) {
                const k = (pB.y - pAPrime.y) / (pB.x - pAPrime.x);
                const pX = (riverY - pAPrime.y) / k + pAPrime.x;
                createSVGElement('line', { x1: pA.x, y1: pA.y, x2: pX, y2: riverY, stroke: '#ef4444', 'stroke-width': 3 });
                createSVGElement('line', { x1: pX, y1: riverY, x2: pB.x, y2: pB.y, stroke: '#ef4444', 'stroke-width': 3 });
                createSVGElement('path', { d: `M ${pAPrime.x} ${pAPrime.y} L ${pB.x} ${pAPrime.y} L ${pB.x} ${pB.y}`, fill: 'none', stroke: '#3b82f6', 'stroke-width': 1, 'stroke-dasharray': '2' });
            }

            // 安全渲染数学公式
            window.renderMath();
        }

        function createSVGElement(type, props) {
            const el = document.createElementNS('http://www.w3.org/2000/svg', type);
            for (let key in props) {
                if (key === 'textContent') {
                    el.textContent = props[key];
                } else {
                    el.setAttribute(key, props[key]);
                }
            }
            dynamicLayer.appendChild(el);
            return el;
        }

        nextBtn.addEventListener('click', () => {
            currentStep = (currentStep + 1) % steps.length;
            updateUI();
        });

        prevBtn.addEventListener('click', () => {
            if (currentStep > 0) {
                currentStep--;
                updateUI();
            }
        });

        // 初始执行一次
        updateUI();
    </script>
</body>
</html>