【博弈论】经典博弈论问题

博弈论 (Game Theory) 是研究多个理性决策者(称为“玩家”)在相互影响的环境中如何做出决策的数学理论。它广泛应用于经济学、政治学、生物学、计算机科学(如人工智能、网络协议设计)等领域。

一、核心概念

  1. 玩家 (Players): 参与博弈的决策主体。
  2. 策略 (Strategies): 每个玩家可选择的行动方案。可以是纯策略(确定的选择)或混合策略(按概率分布选择)。
  3. 收益 (Payoffs): 每个玩家在特定策略组合下的结果(通常用数值表示效用或收益)。
  4. 信息 (Information): 玩家在决策时所知道的信息。分为完全信息(所有玩家知道所有规则和收益)和不完全信息
  5. 均衡 (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 游戏 展示了如何用数学(异或)精确求解特定博弈。
  • 极小化极大 是解决两人零和博弈的经典算法,通过递归搜索博弈树来找到最优策略。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值