This commit is contained in:
parent
fb5a3b8093
commit
58d8b661a8
1055 changed files with 116254 additions and 89 deletions
313
sites/art/src/components/problems/StrategyComparison.tsx
Normal file
313
sites/art/src/components/problems/StrategyComparison.tsx
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
import React, { useMemo } from 'react';
|
||||
|
||||
const StrategyComparison: React.FC = () => {
|
||||
const data = useMemo(() => {
|
||||
const points = [];
|
||||
const maxN = 100;
|
||||
|
||||
for (let n = 5; n <= maxN; n += 5) {
|
||||
// Naive strategy
|
||||
const naiveProb = Math.pow(0.5, n);
|
||||
|
||||
// Loop strategy: 1 - sum(1/k for k from n/2+1 to n)
|
||||
let sum = 0;
|
||||
for (let k = Math.floor(n / 2) + 1; k <= n; k++) {
|
||||
sum += 1 / k;
|
||||
}
|
||||
const loopProb = 1 - sum;
|
||||
|
||||
points.push({ n, naiveProb, loopProb });
|
||||
}
|
||||
|
||||
return points;
|
||||
}, []);
|
||||
|
||||
const chartWidth = 700;
|
||||
const chartHeight = 350;
|
||||
const padding = { top: 20, right: 100, bottom: 50, left: 70 };
|
||||
const width = chartWidth - padding.left - padding.right;
|
||||
const height = chartHeight - padding.top - padding.bottom;
|
||||
|
||||
// Only show loop strategy on linear scale (naive is too small to see)
|
||||
const maxProb = 0.5;
|
||||
|
||||
const getY = (prob: number) => {
|
||||
return height - (prob / maxProb) * height;
|
||||
};
|
||||
|
||||
const getX = (n: number) => {
|
||||
return (n / 100) * width;
|
||||
};
|
||||
|
||||
// Create paths for both strategies
|
||||
const loopPath = data.map((point, i) => {
|
||||
const x = getX(point.n);
|
||||
const y = getY(point.loopProb);
|
||||
return `${i === 0 ? 'M' : 'L'} ${x} ${y}`;
|
||||
}).join(' ');
|
||||
|
||||
// For naive, we'll just show it near zero
|
||||
const naivePath = data.map((point, i) => {
|
||||
const x = getX(point.n);
|
||||
const y = height - 2; // Near the bottom (representing ~0)
|
||||
return `${i === 0 ? 'M' : 'L'} ${x} ${y}`;
|
||||
}).join(' ');
|
||||
|
||||
return (
|
||||
<div className="my-8 p-6 border-2 border-gray-300 rounded-lg bg-white">
|
||||
<h3 className="text-xl font-semibold mb-4">Strategy Comparison</h3>
|
||||
|
||||
<svg width={chartWidth} height={chartHeight} className="mx-auto">
|
||||
<g transform={`translate(${padding.left}, ${padding.top})`}>
|
||||
{/* Grid lines */}
|
||||
{[0, 0.1, 0.2, 0.3, 0.4, 0.5].map((val) => {
|
||||
const y = getY(val);
|
||||
return (
|
||||
<g key={val}>
|
||||
<line
|
||||
x1={0}
|
||||
y1={y}
|
||||
x2={width}
|
||||
y2={y}
|
||||
stroke="#e5e7eb"
|
||||
strokeWidth={1}
|
||||
/>
|
||||
<text
|
||||
x={-10}
|
||||
y={y + 5}
|
||||
textAnchor="end"
|
||||
fontSize="12"
|
||||
fill="#374151"
|
||||
>
|
||||
{val.toFixed(1)}
|
||||
</text>
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* X-axis */}
|
||||
<line
|
||||
x1={0}
|
||||
y1={height}
|
||||
x2={width}
|
||||
y2={height}
|
||||
stroke="#374151"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
|
||||
{/* Y-axis */}
|
||||
<line
|
||||
x1={0}
|
||||
y1={0}
|
||||
x2={0}
|
||||
y2={height}
|
||||
stroke="#374151"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
|
||||
{/* Loop strategy line */}
|
||||
<path
|
||||
d={loopPath}
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
strokeWidth={3}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
|
||||
{/* Naive strategy line (at the bottom) */}
|
||||
<path
|
||||
d={naivePath}
|
||||
fill="none"
|
||||
stroke="#ef4444"
|
||||
strokeWidth={3}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="5,5"
|
||||
/>
|
||||
|
||||
{/* Data points for loop strategy */}
|
||||
{data.filter((_, i) => i % 2 === 0).map((point) => {
|
||||
const x = getX(point.n);
|
||||
const y = getY(point.loopProb);
|
||||
return (
|
||||
<circle
|
||||
key={point.n}
|
||||
cx={x}
|
||||
cy={y}
|
||||
r={4}
|
||||
fill="#10b981"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* X-axis labels */}
|
||||
{[20, 40, 60, 80, 100].map((n) => {
|
||||
const x = getX(n);
|
||||
return (
|
||||
<text
|
||||
key={n}
|
||||
x={x}
|
||||
y={height + 25}
|
||||
textAnchor="middle"
|
||||
fontSize="14"
|
||||
fill="#374151"
|
||||
>
|
||||
{n}
|
||||
</text>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* X-axis title */}
|
||||
<text
|
||||
x={width / 2}
|
||||
y={height + 45}
|
||||
textAnchor="middle"
|
||||
fontSize="16"
|
||||
fontWeight="600"
|
||||
fill="#374151"
|
||||
>
|
||||
Number of Prisoners (n)
|
||||
</text>
|
||||
|
||||
{/* Y-axis title */}
|
||||
<text
|
||||
x={-height / 2}
|
||||
y={-50}
|
||||
textAnchor="middle"
|
||||
fontSize="16"
|
||||
fontWeight="600"
|
||||
fill="#374151"
|
||||
transform={`rotate(-90, ${-height / 2}, -50)`}
|
||||
>
|
||||
Probability of Success
|
||||
</text>
|
||||
|
||||
{/* Legend */}
|
||||
<g transform={`translate(${width + 20}, 20)`}>
|
||||
<rect x={0} y={0} width={15} height={15} fill="#10b981" />
|
||||
<text x={20} y={12} fontSize="14" fill="#374151">
|
||||
Loop Strategy
|
||||
</text>
|
||||
|
||||
<line
|
||||
x1={0}
|
||||
y1={35}
|
||||
x2={15}
|
||||
y2={35}
|
||||
stroke="#ef4444"
|
||||
strokeWidth={3}
|
||||
strokeDasharray="5,5"
|
||||
/>
|
||||
<text x={20} y={40} fontSize="14" fill="#374151">
|
||||
Naive Strategy
|
||||
</text>
|
||||
<text x={20} y={55} fontSize="11" fill="#6b7280">
|
||||
(≈ 0 for all n)
|
||||
</text>
|
||||
</g>
|
||||
|
||||
{/* Highlight key value */}
|
||||
<g>
|
||||
{(() => {
|
||||
const n100Point = data.find(p => p.n === 100);
|
||||
if (n100Point) {
|
||||
const x = getX(100);
|
||||
const y = getY(n100Point.loopProb);
|
||||
return (
|
||||
<>
|
||||
<circle
|
||||
cx={x}
|
||||
cy={y}
|
||||
r={6}
|
||||
fill="none"
|
||||
stroke="#10b981"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
<line
|
||||
x1={x}
|
||||
y1={y - 10}
|
||||
x2={x}
|
||||
y2={y - 40}
|
||||
stroke="#374151"
|
||||
strokeWidth={1}
|
||||
/>
|
||||
<text
|
||||
x={x}
|
||||
y={y - 45}
|
||||
textAnchor="middle"
|
||||
fontSize="12"
|
||||
fontWeight="600"
|
||||
fill="#10b981"
|
||||
>
|
||||
31.18%
|
||||
</text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})()}
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<div className="mt-6 grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="p-4 bg-red-50 border-2 border-red-300 rounded">
|
||||
<h4 className="font-semibold text-red-900 mb-2">❌ Naive Strategy</h4>
|
||||
<p className="text-sm mb-2">
|
||||
Each prisoner randomly selects 50 boxes.
|
||||
</p>
|
||||
<div className="text-xs space-y-1">
|
||||
<p><strong>n=10:</strong> P ≈ {(Math.pow(0.5, 10) * 100).toExponential(2)}%</p>
|
||||
<p><strong>n=20:</strong> P ≈ {(Math.pow(0.5, 20) * 100).toExponential(2)}%</p>
|
||||
<p><strong>n=50:</strong> P ≈ {(Math.pow(0.5, 50) * 100).toExponential(2)}%</p>
|
||||
<p><strong>n=100:</strong> P ≈ {(Math.pow(0.5, 100) * 100).toExponential(2)}%</p>
|
||||
</div>
|
||||
<p className="text-xs mt-2 italic">
|
||||
Essentially impossible for any reasonable n!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-green-50 border-2 border-green-300 rounded">
|
||||
<h4 className="font-semibold text-green-900 mb-2">✅ Loop Strategy</h4>
|
||||
<p className="text-sm mb-2">
|
||||
Each prisoner follows the cycle starting at their number.
|
||||
</p>
|
||||
<div className="text-xs space-y-1">
|
||||
{(() => {
|
||||
const calcProb = (n: number) => {
|
||||
let sum = 0;
|
||||
for (let k = Math.floor(n / 2) + 1; k <= n; k++) {
|
||||
sum += 1 / k;
|
||||
}
|
||||
return ((1 - sum) * 100).toFixed(2);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<p><strong>n=10:</strong> P ≈ {calcProb(10)}%</p>
|
||||
<p><strong>n=20:</strong> P ≈ {calcProb(20)}%</p>
|
||||
<p><strong>n=50:</strong> P ≈ {calcProb(50)}%</p>
|
||||
<p><strong>n=100:</strong> P ≈ {calcProb(100)}%</p>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
<p className="text-xs mt-2 italic">
|
||||
Converges to 1 - ln(2) ≈ 30.69% as n → ∞
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 p-4 bg-blue-50 rounded">
|
||||
<p className="text-sm">
|
||||
<strong>Key Insight:</strong> The loop strategy transforms an impossible problem
|
||||
(probability ≈ 10<sup>-30</sup>) into a reasonable one (probability ≈ 31%).
|
||||
This astronomical improvement comes from exploiting the mathematical structure
|
||||
of permutations rather than relying on independent random trials.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StrategyComparison;
|
||||
Loading…
Add table
Add a link
Reference in a new issue