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 (

Strategy Comparison

{/* Grid lines */} {[0, 0.1, 0.2, 0.3, 0.4, 0.5].map((val) => { const y = getY(val); return ( {val.toFixed(1)} ); })} {/* X-axis */} {/* Y-axis */} {/* Loop strategy line */} {/* Naive strategy line (at the bottom) */} {/* Data points for loop strategy */} {data.filter((_, i) => i % 2 === 0).map((point) => { const x = getX(point.n); const y = getY(point.loopProb); return ( ); })} {/* X-axis labels */} {[20, 40, 60, 80, 100].map((n) => { const x = getX(n); return ( {n} ); })} {/* X-axis title */} Number of Prisoners (n) {/* Y-axis title */} Probability of Success {/* Legend */} Loop Strategy Naive Strategy (≈ 0 for all n) {/* Highlight key value */} {(() => { const n100Point = data.find(p => p.n === 100); if (n100Point) { const x = getX(100); const y = getY(n100Point.loopProb); return ( <> 31.18% ); } return null; })()}

❌ Naive Strategy

Each prisoner randomly selects 50 boxes.

n=10: P ≈ {(Math.pow(0.5, 10) * 100).toExponential(2)}%

n=20: P ≈ {(Math.pow(0.5, 20) * 100).toExponential(2)}%

n=50: P ≈ {(Math.pow(0.5, 50) * 100).toExponential(2)}%

n=100: P ≈ {(Math.pow(0.5, 100) * 100).toExponential(2)}%

Essentially impossible for any reasonable n!

✅ Loop Strategy

Each prisoner follows the cycle starting at their number.

{(() => { 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 ( <>

n=10: P ≈ {calcProb(10)}%

n=20: P ≈ {calcProb(20)}%

n=50: P ≈ {calcProb(50)}%

n=100: P ≈ {calcProb(100)}%

); })()}

Converges to 1 - ln(2) ≈ 30.69% as n → ∞

Key Insight: The loop strategy transforms an impossible problem (probability ≈ 10-30) into a reasonable one (probability ≈ 31%). This astronomical improvement comes from exploiting the mathematical structure of permutations rather than relying on independent random trials.

); }; export default StrategyComparison;