{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6b68f81e",
   "metadata": {},
   "source": [
    "排列组合和概率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0f1f74e3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "导入完成\n"
     ]
    }
   ],
   "source": [
    "import itertools, random\n",
    "from collections import Counter\n",
    "import numpy as np\n",
    "np.random.seed(42)\n",
    "print('导入完成')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4faf1669",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "P(3, 2)排列: [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]\n",
      "数量 =  6  (= 3x2 = 6 )\n"
     ]
    }
   ],
   "source": [
    "# 排列：考虑顺序\n",
    "perms = list(itertools.permutations([1, 2, 3], 2))\n",
    "print('P(3, 2)排列:', perms)\n",
    "print('数量 = ', len(perms), ' (= 3x2 = 6 )')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "6f541819",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C(3, 2)组合: [(1, 2), (1, 3), (2, 3)]\n",
      "数量 =  3  (= 3!/(2!x1!) = 3 )\n"
     ]
    }
   ],
   "source": [
    "combs = list(itertools.combinations([1, 2, 3], 2))\n",
    "print('C(3, 2)组合:', combs)\n",
    "print('数量 = ', len(combs), ' (= 3!/(2!x1!) = 3 )')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "47a635ec",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "P(10, 3) = 720\n",
      "C(10, 3) = 120\n",
      "(52, 5) = 2598960\n"
     ]
    }
   ],
   "source": [
    "def factorial(n):\n",
    "    r = 1\n",
    "    for i in range(2, n+1):    # 从 2 乘到 n\n",
    "        r *= i\n",
    "    return r                   # 返回 n!\n",
    "\n",
    "\n",
    "def P(n, r):                   # 排列 P(n, r) = n! / (n-r)!\n",
    "    r2 = 1\n",
    "    for i in range(r):         # 循环 r 次\n",
    "        r2 *= (n-i)            # n * (n-1) * ... * (n-r+1)\n",
    "    return r2\n",
    "\n",
    "\n",
    "def C(n, r):                   # 组合 C(n, r) = P(n, r) / r!\n",
    "    return P(n, r) // factorial(r)\n",
    "\n",
    "\n",
    "print('P(10, 3) =', P(10, 3))\n",
    "print('C(10, 3) =', C(10, 3))\n",
    "print('(52, 5) =', C(52, 5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "81981c7c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "抛10次: 正面比例 = 0.500\n",
      "抛100次: 正面比例 = 0.370\n",
      "抛1000次: 正面比例 = 0.508\n",
      "抛10000次: 正面比例 = 0.498\n",
      "\n",
      "观察: 抛得越多, 越接近 0.5 — 这是大数定律\n"
     ]
    }
   ],
   "source": [
    "# 大数定律：抛硬币\n",
    "random.seed(0)\n",
    "ratios = []\n",
    "heads = 0\n",
    "\n",
    "for n in range(1, 10001):              # 抛 1 到 10000 次\n",
    "    if random.random() < 0.5:          # 小于 0.5 视为正面\n",
    "        heads += 1                     # 累计正面次数\n",
    "    ratios.append(heads/n)             # 记录当前正面比例\n",
    "\n",
    "print(f'抛10次: 正面比例 = {ratios[9]:.3f}')\n",
    "print(f'抛100次: 正面比例 = {ratios[99]:.3f}')\n",
    "print(f'抛1000次: 正面比例 = {ratios[999]:.3f}')\n",
    "print(f'抛10000次: 正面比例 = {ratios[9999]:.3f}')\n",
    "print()\n",
    "print('观察: 抛得越多, 越接近 0.5 — 这是大数定律')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
