博弈论 (Game Theory) 是研究多个理性决策者(称为“玩家”)在相互影响的环境中如何做出决策的数学理论。它广泛应用于经济学、政治学、生物学、计算机科学(如人工智能、网络协议设计)等领域。
一、核心概念
- 玩家 (Players): 参与博弈的决策主体。
- 策略 (Strategies): 每个玩家可选择的行动方案。可以是纯策略(确定的选择)或混合策略(按概率分布选择)。
- 收益 (Payoffs): 每个玩家在特定策略组合下的结果(通常用数值表示效用或收益)。
- 信息 (Information): 玩家在决策时所知道的信息。分为完全信息(所有玩家知道所有规则和收益)和不完全信息。
- 均衡 (Equilibrium): 一种稳定的状态,其中没有玩家有单方面改变策略的动机。最著名的均衡是纳什均衡 (Nash Equilibrium)。
二、经典博弈模型
1. 囚徒困境 (Prisoner’s Dilemma)
这是最著名的博弈模型,揭示了个人理性选择可能导致集体非最优结果。
- 情境: 两个共谋犯罪的囚徒被分开审讯。他们可以选择坦白或抵赖。
- 收益矩阵:
- 两人都抵赖:各判1年(总刑期2年)。
- 一人坦白,一人抵赖:坦白者释放(0年),抵赖者重判10年。
- 两人都坦白:各判5年(总刑期10年)。
| 玩家A \ 玩家B | 抵赖 (Deny) | 坦白 (Confess) |
|---|---|---|
| 抵赖 (Deny) | (-1, -1) | (-10, 0) |
| 坦白 (Confess) | (0, -10) | (-5, -5) |
- 分析: 对每个玩家而言,“坦白”是占优策略(无论对方选择什么,自己选择坦白都更好)。因此,唯一的纳什均衡是 (坦白, 坦白),结果是 (-5, -5),但这对两人整体来说是最差的结果(总刑期10年),而 (抵赖, 抵赖) 的总刑期只有2年。
2. 零和博弈与极小化极大算法 (Minimax)
零和博弈中,一方的收益等于另一方的损失,总和为零。常用于两人对抗游戏(如国际象棋、围棋)。
- 目标: 最大化自己的最小可能收益(即假设对手会采取最不利于你的策略)。
- 极小化极大算法: 一种递归算法,用于在博弈树中寻找最优策略。
3. Nim 游戏
一个经典的组合博弈,可以用异或 (XOR) 运算求解。
- 规则: 有若干堆石子。两个玩家轮流操作,每次可以从一堆中取走任意正数个石子。取走最后一颗石子的人获胜。
- 关键定理 (Bouton’s Theorem): 一个局面是必败态(对当前要走的玩家不利)当且仅当所有堆石子数的异或和为0。否则是必胜态。
- 策略: 如果异或和不为0,总存在一种取法使得取完后异或和变为0(留给对手一个必败态)。
三、C++ 实现
1. 囚徒困境模拟
#include <iostream>
#include <string>
#include <vector>
// 收益矩阵:[玩家A选择][玩家B选择] -> {A的收益, B的收益}
// 索引: 0 = 抵赖(Deny), 1 = 坦白(Confess)
int payoff[2][2][2] = {
{{-1, -1}, {-10, 0}}, // A抵赖时: B抵赖 -> (-1,-1), B坦白 -> (-10, 0)
{{0, -10}, {-5, -5}} // A坦白时: B抵赖 -> (0, -10), B坦白 -> (-5, -5)
};
std::string strategyToString(int s) {
return s == 0 ? "Deny" : "Confess";
}
void simulatePrisonersDilemma(int strategyA, int strategyB) {
std::cout << "Player A chooses: " << strategyToString(strategyA) << std::endl;
std::cout << "Player B chooses: " << strategyToString(strategyB) << std::endl;
int payoffA = payoff[strategyA][strategyB][0];
int payoffB = payoff[strategyA][strategyB][1];
std::cout << "Payoff: A = " << payoffA << " years, B = " << payoffB << " years" << std::endl;
// 分析纳什均衡
if (strategyA == 1 && strategyB == 1) {
std::cout << "This is a Nash Equilibrium (both have dominant strategy to Confess)." << std::endl;
} else {
std::cout << "This is NOT a Nash Equilibrium." << std::endl;
}
}
int main() {
std::cout << "=== Prisoner's Dilemma Simulation ===" << std::endl;
// 模拟不同策略组合
simulatePrisonersDilemma(0, 0); // 两人都抵赖
std::cout << "---" << std::endl;
simulatePrisonersDilemma(1, 0); // A坦白,B抵赖
std::cout << "---" << std::endl;
simulatePrisonersDilemma(0, 1); // A抵赖,B坦白
std::cout << "---" << std::endl;
simulatePrisonersDilemma(1, 1); // 两人都坦白 (Nash Equilibrium)
return 0;
}
2. Nim 游戏求解器
#include <iostream>
#include <vector>
class NimGame {
private:
std::vector<int> piles; // 各堆石子数量
public:
NimGame(const std::vector<int>& initialPiles) : piles(initialPiles) {}
// 计算当前局面的 Nim 和 (XOR of all pile sizes)
int calculateNimSum() const {
int nimSum = 0;
for (int pile : piles) {
nimSum ^= pile;
}
return nimSum;
}
// 判断当前玩家是否处于必胜态
bool isWinningPosition() const {
return calculateNimSum() != 0;
}
// 找到一个必胜移动 (如果存在)
// 返回: {堆索引, 要取走的石子数},如果无必胜移动则返回 {-1, -1}
std::pair<int, int> findWinningMove() const {
int nimSum = calculateNimSum();
if (nimSum == 0) {
return {-1, -1}; // 当前是必败态,无必胜移动
}
// 寻找一个堆,使得其石子数 XOR nimSum < 其当前石子数
for (int i = 0; i < piles.size(); ++i) {
int targetSize = piles[i] ^ nimSum;
if (targetSize < piles[i]) {
int stonesToRemove = piles[i] - targetSize;
return {i, stonesToRemove};
}
}
return {-1, -1}; // 理论上不会到达这里
}
// 模拟一次移动
bool makeMove(int pileIndex, int stonesToRemove) {
if (pileIndex < 0 || pileIndex >= piles.size() ||
stonesToRemove <= 0 || stonesToRemove > piles[pileIndex]) {
std::cout << "Invalid move!" << std::endl;
return false;
}
piles[pileIndex] -= stonesToRemove;
return true;
}
// 检查游戏是否结束 (所有堆为空)
bool isGameOver() const {
for (int pile : piles) {
if (pile > 0) return false;
}
return true;
}
void printState() const {
std::cout << "Current piles: ";
for (int pile : piles) {
std::cout << pile << " ";
}
std::cout << "(Nim Sum: " << calculateNimSum() << ")" << std::endl;
}
};
int main() {
std::cout << "=== Nim Game Solver ===" << std::endl;
std::vector<int> initialPiles = {3, 4, 5};
NimGame game(initialPiles);
game.printState();
if (game.isWinningPosition()) {
std::cout << "Current player is in a WINNING position!" << std::endl;
auto move = game.findWinningMove();
if (move.first != -1) {
std::cout << "Recommended winning move: Take " << move.second
<< " stone(s) from pile " << (move.first + 1) << std::endl;
}
} else {
std::cout << "Current player is in a LOSING position (if opponent plays perfectly)." << std::endl;
}
// 模拟一次移动
std::cout << "\nMaking move: Take 2 stones from pile 1 (index 0)" << std::endl;
game.makeMove(0, 2); // 取2个,堆变为1
game.printState();
return 0;
}
3. 极小化极大算法 (用于类似井字棋的博弈)
#include <iostream>
#include <vector>
#include <climits>
const int EMPTY = 0;
const int PLAYER_X = 1;
const int PLAYER_O = -1;
class TicTacToe {
private:
std::vector<std::vector<int>> board;
// 评估当前局面
int evaluate() {
// 检查行、列、对角线
for (int i = 0; i < 3; i++) {
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
return board[i][0];
}
if (board[0][i] == board[1][i] && board[1][i] == board[2][i]) {
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
return board[0][2];
}
return 0; // 平局或未结束
}
// 检查游戏是否结束
bool isMovesLeft() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (board[i][j] == EMPTY)
return true;
return false;
}
// 极小化极大核心函数
int minimax(int depth, bool isMaximizing) {
int score = evaluate();
// 如果X赢了,返回高分
if (score == PLAYER_X) return 10 - depth;
// 如果O赢了,返回低分
if (score == PLAYER_O) return depth - 10;
// 如果平局,返回0
if (!isMovesLeft()) return 0;
if (isMaximizing) {
int best = INT_MIN;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == EMPTY) {
board[i][j] = PLAYER_X;
best = std::max(best, minimax(depth + 1, false));
board[i][j] = EMPTY; // 撤销移动
}
}
}
return best;
} else {
int best = INT_MAX;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == EMPTY) {
board[i][j] = PLAYER_O;
best = std::min(best, minimax(depth + 1, true));
board[i][j] = EMPTY; // 撤销移动
}
}
}
return best;
}
}
public:
TicTacToe() : board(3, std::vector<int>(3, EMPTY)) {}
// 找到最佳移动
std::pair<int, int> findBestMove() {
int bestVal = INT_MIN;
std::pair<int, int> bestMove = {-1, -1};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == EMPTY) {
board[i][j] = PLAYER_X; // 假设AI是X
int moveVal = minimax(0, false);
board[i][j] = EMPTY;
if (moveVal > bestVal) {
bestMove = {i, j};
bestVal = moveVal;
}
}
}
}
return bestMove;
}
void makeMove(int row, int col, int player) {
if (row >= 0 && row < 3 && col >= 0 && col < 3 && board[row][col] == EMPTY) {
board[row][col] = player;
}
}
void printBoard() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
char c = ' ';
if (board[i][j] == PLAYER_X) c = 'X';
else if (board[i][j] == PLAYER_O) c = 'O';
std::cout << c;
if (j < 2) std::cout << " | ";
}
std::cout << std::endl;
if (i < 2) std::cout << "---------" << std::endl;
}
std::cout << std::endl;
}
};
int main() {
std::cout << "=== Tic-Tac-Toe AI (Minimax) ===" << std::endl;
TicTacToe game;
game.printBoard();
auto bestMove = game.findBestMove();
std::cout << "Best move for X is: Row " << bestMove.first << ", Col " << bestMove.second << std::endl;
// 模拟AI走第一步
game.makeMove(bestMove.first, bestMove.second, PLAYER_X);
game.printBoard();
return 0;
}
四、 总结
- 博弈论 提供了分析策略互动的框架。
- 囚徒困境 展示了个人理性与集体理性的冲突。
- Nim 游戏 展示了如何用数学(异或)精确求解特定博弈。
- 极小化极大 是解决两人零和博弈的经典算法,通过递归搜索博弈树来找到最优策略。

被折叠的 条评论
为什么被折叠?



