鸽巢问题(红球蓝球)edit icon

创建者:
Fork(复制)
下载
嵌入
BUG反馈
index.html
index.html
            
            <!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>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            line-height: 1.6;
            background-color: #f8f9fa;
            color: #333;
        }
        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            background-color: white;
            border-radius: 12px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
            padding: 30px;
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 30px;
            text-align: center;
            font-weight: 700;
        }
        .problem {
            font-size: 18px;
            text-align: center;
            margin-bottom: 30px;
            background-color: #f1f8e9;
            padding: 15px;
            border-radius: 8px;
            border-left: 5px solid #8bc34a;
        }
        .box {
            width: 320px;
            height: 160px;
            border: 3px solid #34495e;
            border-radius: 12px;
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 20px 0;
            padding: 15px;
            background-color: #ecf0f1;
            position: relative;
            flex-wrap: wrap;
            box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
        }
        .box::before {
            content: "盒子";
            position: absolute;
            top: -15px;
            background: white;
            padding: 5px 15px;
            border-radius: 20px;
            font-weight: bold;
            color: #34495e;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .ball {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            margin: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-weight: bold;
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
            transition: transform 0.3s ease;
        }
        .ball:hover {
            transform: scale(1.1);
        }
        .red {
            background: linear-gradient(135deg, #ff5252, #b71c1c);
        }
        .blue {
            background: linear-gradient(135deg, #4285f4, #0d47a1);
        }
        .selection {
            margin-top: 30px;
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 100%;
        }
        .buttons {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 10px;
            margin-top: 15px;
        }
        .draw-btn {
            padding: 12px 24px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 30px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }
        .draw-btn:hover {
            background-color: #2980b9;
            transform: translateY(-2px);
            box-shadow: 0 6px 8px rgba(0,0,0,0.15);
        }
        .draw-btn:active {
            transform: translateY(1px);
        }
        .reset-btn {
            background-color: #e74c3c;
        }
        .reset-btn:hover {
            background-color: #c0392b;
        }
        .find-btn {
            background-color: #9b59b6;
        }
        .find-btn:hover {
            background-color: #8e44ad;
        }
        .result {
            margin-top: 30px;
            font-size: 18px;
            text-align: center;
            padding: 15px;
            border-radius: 8px;
            background-color: #e3f2fd;
            width: 100%;
            max-width: 500px;
            transition: all 0.3s ease;
        }
        .drawn-balls {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            margin-top: 25px;
            padding: 15px;
            background-color: #f5f5f5;
            border-radius: 12px;
            min-height: 70px;
            width: 100%;
            max-width: 500px;
        }
        .counterexample {
            margin-top: 25px;
            padding: 20px;
            background-color: #ffebee;
            border-radius: 8px;
            display: none;
            font-weight: 500;
            border-left: 5px solid #f44336;
            width: 100%;
            max-width: 500px;
        }
        .stats {
            margin-top: 30px;
            padding: 20px;
            background-color: #e8f5e9;
            border-radius: 8px;
            width: 100%;
            max-width: 500px;
            text-align: center;
            border-left: 5px solid #4caf50;
        }
        .stat-item {
            margin: 10px 0;
            font-size: 16px;
        }
        .progress-bar {
            height: 8px;
            background-color: #eceff1;
            border-radius: 4px;
            margin-top: 8px;
            overflow: hidden;
        }
        .progress {
            height: 100%;
            border-radius: 4px;
            transition: width 0.5s ease;
        }
        .progress-3 {
            background-color: #ff9800;
        }
        .progress-3.full {
            background-color: #4caf50;
        }
        .progress-4 {
            background-color: #4caf50;
        }
        .conclusion {
            margin-top: 40px;
            padding: 20px;
            background-color: #fff8e1;
            border-radius: 8px;
            font-weight: 500;
            border-left: 5px solid #ffc107;
            width: 100%;
            max-width: 500px;
        }
        .explanation {
            margin-top: 30px;
            padding: 20px;
            background-color: #f9f9f9;
            border-radius: 8px;
            width: 100%;
            max-width: 500px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        }
        .highlight {
            color: #4CAF50;
            font-size: 24px;
            font-weight: bold;
        }
        @media (max-width: 600px) {
            .box {
                width: 90%;
            }
            .ball {
                width: 40px;
                height: 40px;
                margin: 6px;
            }
            .buttons {
                flex-direction: column;
                width: 100%;
            }
            .draw-btn {
                width: 100%;
                margin: 5px 0;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>球的抽取问题</h1>
        <div class="problem">
            盒子里有同样大小的红球和蓝球各4个,要想摸出的球一定有2个同色的,至少要摸出几个球?
        </div>
        
        <div class="box" id="box">
            <div class="ball red">R</div>
            <div class="ball red">R</div>
            <div class="ball red">R</div>
            <div class="ball red">R</div>
            <div class="ball blue">B</div>
            <div class="ball blue">B</div>
            <div class="ball blue">B</div>
            <div class="ball blue">B</div>
        </div>
        
        <div class="selection">
            <p>请尝试摸球实验:</p>
            <div class="buttons">
                <button class="draw-btn" onclick="drawBalls(2)">摸2个球</button>
                <button class="draw-btn" onclick="drawBalls(3)">摸3个球</button>
                <button class="draw-btn find-btn" onclick="findCounterexample(2)">寻找反例(2个球)</button>
                <button class="draw-btn" onclick="tryMultipleTimes(2, 10)">摸2个球10次</button>
                <button class="draw-btn" onclick="tryMultipleTimes(3, 10)">摸3个球10次</button>
                <button class="draw-btn reset-btn" onclick="reset()">重置</button>
            </div>
        </div>
        
        <div class="result" id="result"></div>
        <div class="drawn-balls" id="drawnBalls"></div>
        
        <div class="counterexample" id="counterexample">
            反例:当摸出2个球时,可能出现<span style="color: #ff5252;">1个红球</span>和<span style="color: #4285f4;">1个蓝球</span>的情况,这样就没有至少2个同色的球。
        </div>
        
        <div class="stats" id="stats">
            <h3>统计数据</h3>
            <div id="statsContent"></div>
        </div>
        
        <div class="conclusion">
            结论:至少需要摸出<span class="highlight">2+1=3</span>个球,才能保证一定有2个同色的球。
        </div>
        
        <div class="explanation">
            <h3>解释:</h3>
            <p>根据鸽巢原理(抽屉原理):</p>
            <p>我们有2种颜色(红色和蓝色),如果要确保至少有2个球是同色的,根据鸽巢原理,需要摸出的球数至少为2+1=3个。</p>
            <p>当摸出2个球时,可能是1红1蓝,此时没有同色球。</p>
            <p>但当摸出3个球时,无论如何分配这3个球的颜色,必定至少有2个球是同色的:</p>
            <ul>
                <li>可能是3个红球 → 有3个同色球</li>
                <li>可能是2个红球+1个蓝球 → 有2个同色球</li>
                <li>可能是1个红球+2个蓝球 → 有2个同色球</li>
                <li>可能是3个蓝球 → 有3个同色球</li>
            </ul>
            <p>所以,要保证至少有2个同色球,最少需要摸出3个球。</p>
        </div>
    </div>

    <script>
        const colors = ['red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue'];
        let remainingBalls = [...colors];
        let statsData = {
            draw2: { total: 0, withSameColor: 0 },
            draw3: { total: 0, withSameColor: 0 }
        };
        
        function drawBalls(count) {
            if (remainingBalls.length < count) {
                document.getElementById('result').innerHTML = "盒子里没有足够的球了,请重置";
                return;
            }
            
            // 随机抽取球
            const drawn = [];
            for (let i = 0; i < count; i++) {
                const randomIndex = Math.floor(Math.random() * remainingBalls.length);
                drawn.push(remainingBalls[randomIndex]);
                remainingBalls.splice(randomIndex, 1);
            }
            
            // 检查是否有同色球
            const redCount = drawn.filter(color => color === 'red').length;
            const blueCount = drawn.filter(color => color === 'blue').length;
            
            const hasSameColor = redCount >= 2 || blueCount >= 2;
            
            // 更新统计数据
            if (count === 2) {
                statsData.draw2.total++;
                if (hasSameColor) statsData.draw2.withSameColor++;
            } else if (count === 3) {
                statsData.draw3.total++;
                if (hasSameColor) statsData.draw3.withSameColor++;
            }
            
            // 更新盒子中的球
            updateBox();
            
            // 显示抽出的球
            const drawnBallsDiv = document.getElementById('drawnBalls');
            drawnBallsDiv.innerHTML = '';
            drawn.forEach(color => {
                const ball = document.createElement('div');
                ball.className = `ball ${color}`;
                ball.textContent = color === 'red' ? 'R' : 'B';
                drawnBallsDiv.appendChild(ball);
            });
            
            // 显示结果
            let resultText = `摸出了${count}个球(${redCount}个红球,${blueCount}个蓝球)`;
            if (hasSameColor) {
                resultText += "<br>✓ 确实有至少2个同色的球!";
                document.getElementById('result').style.backgroundColor = "#e8f5e9";
                document.getElementById('result').style.borderLeft = "5px solid #4caf50";
            } else {
                resultText += "<br>✗ 没有至少2个同色的球!";
                document.getElementById('result').style.backgroundColor = "#ffebee";
                document.getElementById('result').style.borderLeft = "5px solid #f44336";
                if (count === 2) {
                    document.getElementById('counterexample').style.display = 'block';
                }
            }
            document.getElementById('result').innerHTML = resultText;
            
            // 更新统计
            updateStats();
            
            return { drawn, hasSameColor };
        }
        
        function findCounterexample(count) {
            reset();
            // 强制寻找反例:对于2个球,找到1红1蓝的情况
            let foundCounterexample = false;
            let attempts = 0;
            const maxAttempts = 50;
            
            while (!foundCounterexample && attempts < maxAttempts) {
                reset();
                const result = drawBalls(count);
                const redCount = result.drawn.filter(color => color === 'red').length;
                const blueCount = result.drawn.filter(color => color === 'blue').length;
                
                if (count === 2 && redCount === 1 && blueCount === 1) {
                    foundCounterexample = true;
                    document.getElementById('counterexample').style.display = 'block';
                }
                attempts++;
            }
            
            if (!foundCounterexample) {
                document.getElementById('result').innerHTML += "<br>尝试了" + maxAttempts + "次,未能找到反例,请再试一次。";
            }
        }
        
        function tryMultipleTimes(count, times) {
            reset();
            let successCount = 0;
            
            for (let i = 0; i < times; i++) {
                reset();
                const result = drawBalls(count);
                if (result.hasSameColor) {
                    successCount++;
                }
            }
            
            const successRate = (successCount / times * 100).toFixed(2);
            
            document.getElementById('result').innerHTML = 
                `尝试摸${count}个球${times}次,有${successCount}次找到至少2个同色球。` +
                `<br>概率:${successRate}%`;
            
            document.getElementById('result').style.backgroundColor = "#e3f2fd";
            document.getElementById('result').style.borderLeft = "5px solid #2196f3";
                
            if (count === 2 && successRate < 100) {
                document.getElementById('counterexample').style.display = 'block';
            } else if (count === 3 && successRate === 100) {
                document.getElementById('result').innerHTML += "<br>✓ 摸3个球时,100%能保证有至少2个同色球!";
                document.getElementById('result').style.backgroundColor = "#e8f5e9";
                document.getElementById('result').style.borderLeft = "5px solid #4caf50";
            }
        }
        
        function updateBox() {
            const boxDiv = document.getElementById('box');
            boxDiv.innerHTML = '';
            remainingBalls.forEach(color => {
                const ball = document.createElement('div');
                ball.className = `ball ${color}`;
                ball.textContent = color === 'red' ? 'R' : 'B';
                boxDiv.appendChild(ball);
            });
        }
        
        function updateStats() {
            const statsDiv = document.getElementById('statsContent');
            statsDiv.innerHTML = '';
            
            if (statsData.draw2.total > 0) {
                const rate2 = (statsData.draw2.withSameColor / statsData.draw2.total * 100).toFixed(2);
                const div = document.createElement('div');
                div.className = 'stat-item';
                div.innerHTML = `摸2个球:${statsData.draw2.withSameColor}/${statsData.draw2.total} 次有至少2个同色球 (${rate2}%)
                                <div class="progress-bar">
                                    <div class="progress progress-3 ${rate2 == 100 ? 'full' : ''}" style="width: ${rate2}%"></div>
                                </div>`;
                statsDiv.appendChild(div);
            }
            
            if (statsData.draw3.total > 0) {
                const rate3 = (statsData.draw3.withSameColor / statsData.draw3.total * 100).toFixed(2);
                const div = document.createElement('div');
                div.className = 'stat-item';
                div.innerHTML = `摸3个球:${statsData.draw3.withSameColor}/${statsData.draw3.total} 次有至少2个同色球 (${rate3}%)
                                <div class="progress-bar">
                                    <div class="progress progress-4" style="width: ${rate3}%"></div>
                                </div>`;
                statsDiv.appendChild(div);
            }
        }
        
        function reset() {
            remainingBalls = [...colors];
            updateBox();
            document.getElementById('result').innerHTML = '';
            document.getElementById('result').style.backgroundColor = "#e3f2fd";
            document.getElementById('result').style.borderLeft = "5px solid #2196f3";
            document.getElementById('drawnBalls').innerHTML = '';
            document.getElementById('counterexample').style.display = 'none';
        }
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台