<!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>
index.html
index.html