大富翁(Monopoly)是全球最经典的桌游之一,玩家通过掷骰子在环形地图上行进,购买地产、收取租金,最终使对手破产获胜。看似依赖运气的背后,隐藏着图论建模、马尔可夫链概率计算、蒙特卡洛模拟估值与动态规划决策四大算法核心。本文将用Java完整实现大富翁的AI决策引擎,从地图建模到最优买地策略逐层剖析。
一、地图图论建模
1.1 为什么用有向图建模
标准大富翁地图由40个格子组成环形路径,每个格子代表一个状态节点。玩家从当前位置掷骰子(2个六面骰)后,根据点数之和移动到目标位置。这种移动规则天然适合用有向带权图建模:
- 节点:每个地图格子(起点、地产、机会、监狱等)
- 有向边:从节点A到节点B的可达路径
- 边权重:从A掷骰子到达B的精确概率
1.2 地图节点定义
/**
* 地图格子类型枚举
*/
enum CellType {
START, // 起点(经过发2000)
PROPERTY, // 可购买地产
TAX, // 税收
CHANCE, // 机会卡
JAIL, // 监狱
GOTO_JAIL, // 送监狱
UTILITY, // 公共设施
STATION // 车站
}
/**
* 地图格子节点
*/
class BoardCell {
// 格子编号,0-39
int id;
// 格子名称
String name;
// 格子类型
CellType type;
// 购买价格(地产类有效)
int price;
// 基础租金(地产类有效)
int baseRent;
// 所属玩家,-1表示无人拥有
int owner;
// 是否有房屋
int houses;
// 最大可建房屋数
static final int MAX_HOUSES = 5;
BoardCell(int id, String name, CellType type, int price, int baseRent) {
this.id = id;
this.name = name;
this.type = type;
this.price = price;
this.baseRent = baseRent;
this.owner = -1;
this.houses = 0;
}
/**
* 计算当前租金
* 有房屋时租金按指数增长:基础租金 * (houses + 1)^2
*/
int getCurrentRent() {
if (type != CellType.PROPERTY && type != CellType.UTILITY && type != CellType.STATION) {
return 0;
}
if (owner == -1) return 0;
return baseRent * (houses + 1) * (houses + 1);
}
@Override
public String toString() {
return String.format("%s[%d](%s)", name, id, type);
}
}
1.3 标准40格地图初始化
/**
* 大富翁游戏棋盘
* 维护40个格子的状态与玩家位置
*/
class MonopolyBoard {
static final int BOARD_SIZE = 40;
private final BoardCell[] cells;
// 玩家位置:playerPositions[playerId] = cellId
private final int[] playerPositions;
// 玩家资金
private final int[] playerMoney;
private final int playerCount;
MonopolyBoard(int playerCount) {
this.playerCount = playerCount;
this.cells = new BoardCell[BOARD_SIZE];
this.playerPositions = new int[playerCount];
this.playerMoney = new int[playerCount];
initStandardBoard();
for (int i = 0; i < playerCount; i++) {
playerPositions[i] = 0;
playerMoney[i] = 15000; // 初始资金
}
}
/**
* 初始化标准大富翁地图(简化版核心地产)
*/
private void initStandardBoard() {
cells[0] = new BoardCell(0, "起点", CellType.START, 0, 0);
cells[1] = new BoardCell(1, "北京路", CellType.PROPERTY, 600, 20);
cells[2] = new BoardCell(2, "社区宝箱", CellType.CHANCE, 0, 0);
cells[3] = new BoardCell(3, "上海路", CellType.PROPERTY, 600, 40);
cells[4] = new BoardCell(4, "所得税", CellType.TAX, 0, 200);
cells[5] = new BoardCell(5, "火车站", CellType.STATION, 2000, 100);
cells[6] = new BoardCell(6, "广州路", CellType.PROPERTY, 1000, 60);
cells[7] = new BoardCell(7, "机会卡", CellType.CHANCE, 0, 0);
cells[8] = new BoardCell(8, "深圳路", CellType.PROPERTY, 1000, 60);
cells[9] = new BoardCell(9, "杭州路", CellType.PROPERTY, 1200, 80);
cells[10] = new BoardCell(10, "监狱", CellType.JAIL, 0, 0);
cells[11] = new BoardCell(11, "南京路", CellType.PROPERTY, 1400, 100);
cells[12] = new BoardCell(12, "电力公司", CellType.UTILITY, 1500, 0);
cells[13] = new BoardCell(13, "成都路", CellType.PROPERTY, 1400, 100);
cells[14] = new BoardCell(14, "重庆路", CellType.PROPERTY, 1600, 120);
cells[15] = new BoardCell(15, "汽车站", CellType.STATION, 2000, 100);
cells[16] = new BoardCell(16, "武汉路", CellType.PROPERTY, 1800, 140);
cells[17] = new BoardCell(17, "社区宝箱", CellType.CHANCE, 0, 0);
cells[18] = new BoardCell(18, "西安路", CellType.PROPERTY, 1800, 140);
cells[19] = new BoardCell(19, "天津路", CellType.PROPERTY, 2000, 160);
cells[20] = new BoardCell(20, "免费停车", CellType.START, 0, 0);
cells[21] = new BoardCell(21, "沈阳路", CellType.PROPERTY, 2200, 180);
cells[22] = new BoardCell(22, "机会卡", CellType.CHANCE, 0, 0);
cells[23] = new BoardCell(23, "青岛路", CellType.PROPERTY, 2200, 180);
cells[24] = new BoardCell(24, "大连路", CellType.PROPERTY, 2400, 200);
cells[25] = new BoardCell(25, "港口", CellType.STATION, 2000, 100);
cells[26] = new BoardCell(26, "苏州路", CellType.PROPERTY, 2600, 220);
cells[27] = new BoardCell(27, "厦门路", CellType.PROPERTY, 2600, 220);
cells[28] = new BoardCell(28, "自来水厂", CellType.UTILITY, 1500, 0);
cells[29] = new BoardCell(29, "宁波路", CellType.PROPERTY, 2800, 240);
cells[30] = new BoardCell(30, "进监狱", CellType.GOTO_JAIL, 0, 0);
cells[31] = new BoardCell(31, "长沙路", CellType.PROPERTY, 3000, 260);
cells[32] = new BoardCell(32, "哈尔滨路", CellType.PROPERTY, 3000, 260);
cells[33] = new BoardCell(33, "社区宝箱", CellType.CHANCE, 0, 0);
cells[34] = new BoardCell(34, "郑州路", CellType.PROPERTY, 3200, 280);
cells[35] = new BoardCell(35, "机场", CellType.STATION, 2000, 100);
cells[36] = new BoardCell(36, "机会卡", CellType.CHANCE, 0, 0);
cells[37] = new BoardCell(37, "昆明路", CellType.PROPERTY, 3500, 350);
cells[38] = new BoardCell(38, "奢侈税", CellType.TAX, 0, 100);
cells[39] = new BoardCell(39, "香港路", CellType.PROPERTY, 4000, 500);
}
BoardCell getCell(int id) {
return cells[id % BOARD_SIZE];
}
int getPlayerPosition(int playerId) {
return playerPositions[playerId];
}
void movePlayer(int playerId, int steps) {
int oldPos = playerPositions[playerId];
int newPos = (oldPos + steps) % BOARD_SIZE;
// 经过起点奖励
if (newPos < oldPos && newPos != 0) {
playerMoney[playerId] += 2000;
}
playerPositions[playerId] = newPos;
}
void setPlayerPosition(int playerId, int pos) {
playerPositions[playerId] = pos % BOARD_SIZE;
}
int getPlayerMoney(int playerId) {
return playerMoney[playerId];
}
void addMoney(int playerId, int amount) {
playerMoney[playerId] += amount;
}
boolean isBankrupt(int playerId) {
return playerMoney[playerId] <= 0;
}
}
二、核心算法一:马尔可夫链掷骰概率
2.1 两个六面骰的概率分布
大富翁使用两个六面骰,点数之和的概率呈三角形分布:
/**
* 掷骰子概率计算器
* 两个六面骰,和为2-12的概率
*/
class DiceProbability {
// 点数和 -> 精确概率
static final double[] PROB = new double[13];
// 点数和 -> 出现方式数
static final int[] WAYS = new int[13];
static {
// 计算每种和的方式数
for (int d1 = 1; d1 <= 6; d1++) {
for (int d2 = 1; d2 <= 6; d2++) {
WAYS[d1 + d2]++;
}
}
// 转换为概率
for (int s = 2; s <= 12; s++) {
PROB[s] = WAYS[s] / 36.0;
}
}
/**
* 从当前位置出发,到达每个格子的精确概率
* @param from 起始位置
* @return 到达各格子的概率数组
*/
static double[] reachProbability(int from) {
double[] prob = new double[MonopolyBoard.BOARD_SIZE];
for (int sum = 2; sum <= 12; sum++) {
int target = (from + sum) % MonopolyBoard.BOARD_SIZE;
prob[target] += PROB[sum];
}
return prob;
}
/**
* 打印概率分布验证
*/
static void printDistribution() {
System.out.println("=== 两个六面骰概率分布 ===");
for (int s = 2; s <= 12; s++) {
System.out.printf("和=%d: 方式=%d, 概率=%.4f%n", s, WAYS[s], PROB[s]);
}
}
}
2.2 多步转移概率矩阵
/**
* 马尔可夫链转移矩阵
* 计算从任意格子出发,N步后到达各格子的概率
*/
class MarkovChain {
private final double[][] transitionMatrix;
private final int size;
MarkovChain(int boardSize) {
this.size = boardSize;
this.transitionMatrix = new double[boardSize][boardSize];
buildTransitionMatrix();
}
/**
* 构建单步转移矩阵
* matrix[i][j] = 从i出发一步到达j的概率
*/
private void buildTransitionMatrix() {
for (int i = 0; i < size; i++) {
double[] reach = DiceProbability.reachProbability(i);
System.arraycopy(reach, 0, transitionMatrix[i], 0, size);
}
}
/**
* 计算N步转移概率
* 使用矩阵快速幂优化,时间复杂度O(size^3 * logN)
* @param from 起始位置
* @param steps 步数
* @return N步后到达各位置的概率
*/
double[] nStepProbability(int from, int steps) {
// 初始状态向量
double[] state = new double[size];
state[from] = 1.0;
// 快速幂计算矩阵的steps次幂作用于状态向量
double[][] mat = matrixPower(transitionMatrix, steps);
double[] result = new double[size];
for (int j = 0; j < size; j++) {
result[j] = mat[from][j];
}
return result;
}
/**
* 矩阵快速幂
*/
private double[][] matrixPower(double[][] base, int exp) {
double[][] result = identityMatrix(size);
double[][] b = copyMatrix(base);
int e = exp;
while (e > 0) {
if ((e & 1) == 1) {
result = multiplyMatrix(result, b);
}
b = multiplyMatrix(b, b);
e >>= 1;
}
return result;
}
private double[][] identityMatrix(int n) {
double[][] m = new double[n][n];
for (int i = 0; i < n; i++) m[i][i] = 1.0;
return m;
}
private double[][] copyMatrix(double[][] src) {
double[][] dst = new double[src.length][src[0].length];
for (int i = 0; i < src.length; i++) {
System.arraycopy(src[i], 0, dst[i], 0, src[i].length);
}
return dst;
}
private double[][] multiplyMatrix(double[][] a, double[][] b) {
double[][] c = new double[size][size];
for (int i = 0; i < size; i++) {
for (int k = 0; k < size; k++) {
if (a[i][k] == 0) continue;
for (int j = 0; j < size; j++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
return c;
}
/**
* 计算稳态分布(长期游戏中每个格子被访问的频率)
* 使用幂迭代法逼近特征向量
*/
double[] stationaryDistribution(int iterations) {
double[] dist = new double[size];
dist[0] = 1.0; // 从起点开始
for (int iter = 0; iter < iterations; iter++) {
double[] next = new double[size];
for (int j = 0; j < size; j++) {
for (int i = 0; i < size; i++) {
next[j] += dist[i] * transitionMatrix[i][j];
}
}
dist = next;
}
return dist;
}
}
三、核心算法二:蒙特卡洛地产估值
3.1 为什么需要蒙特卡洛模拟
大富翁中地产的实际价值不仅取决于租金,还取决于被对手踩中的概率、建成房屋后的增值潜力、同色垄断加成等复杂因素。蒙特卡洛模拟通过大量随机对局,统计各地产对胜率的实际贡献。
3.2 模拟器核心
import java.util.*;
/**
* 大富翁单局模拟器
* 执行一局快速对局,记录各地产被踩中次数与最终资金
*/
class GameSimulator {
private final Random random;
private final int playerCount;
private final int maxRounds;
GameSimulator(int playerCount, int maxRounds, long seed) {
this.playerCount = playerCount;
this.maxRounds = maxRounds;
this.random = new Random(seed);
}
/**
* 模拟一局游戏
* @param board 初始棋盘(可预设地产归属)
* @return 各格子被踩中总次数
*/
int[] simulate(MonopolyBoard board) {
int[] visitCount = new int[MonopolyBoard.BOARD_SIZE];
int activePlayers = playerCount;
for (int round = 0; round < maxRounds && activePlayers > 1; round++) {
for (int p = 0; p < playerCount; p++) {
if (board.isBankrupt(p)) continue;
// 掷两个骰子
int d1 = random.nextInt(6) + 1;
int d2 = random.nextInt(6) + 1;
int steps = d1 + d2;
int oldPos = board.getPlayerPosition(p);
board.movePlayer(p, steps);
int newPos = board.getPlayerPosition(p);
visitCount[newPos]++;
// 处理格子效果
handleCellEffect(board, p, newPos);
// 破产检测
if (board.isBankrupt(p)) {
activePlayers--;
}
}
}
return visitCount;
}
/**
* 处理玩家落在某格子的效果
*/
private void handleCellEffect(MonopolyBoard board, int playerId, int pos) {
BoardCell cell = board.getCell(pos);
switch (cell.type) {
case TAX:
board.addMoney(playerId, -cell.baseRent);
break;
case GOTO_JAIL:
board.setPlayerPosition(playerId, 10);
break;
case PROPERTY:
case STATION:
case UTILITY:
if (cell.owner != -1 && cell.owner != playerId) {
// 支付租金
int rent = cell.getCurrentRent();
board.addMoney(playerId, -rent);
board.addMoney(cell.owner, rent);
}
break;
case CHANCE:
// 简化:机会卡随机移动
int chanceMove = random.nextInt(5) - 2; // -2到+2
if (chanceMove != 0) {
board.movePlayer(playerId, chanceMove);
handleCellEffect(board, playerId, board.getPlayerPosition(playerId));
}
break;
default:
break;
}
}
}
3.3 地产价值评估
/**
* 蒙特卡洛地产估值器
* 通过大量模拟计算每块地产的期望收益
*/
class PropertyEvaluator {
private final int simulations;
private final GameSimulator simulator;
PropertyEvaluator(int simulations) {
this.simulations = simulations;
this.simulator = new GameSimulator(4, 100, 42);
}
/**
* 评估指定地产的价值
* 模拟当前玩家拥有该地产后的100局游戏,统计净收益
* @param propertyId 地产格子ID
* @return 期望净收益(考虑购买成本)
*/
double evaluatePropertyValue(int propertyId) {
long totalProfit = 0;
for (int sim = 0; sim < simulations; sim++) {
MonopolyBoard board = new MonopolyBoard(4);
// 预设当前玩家(0号)拥有该地产
BoardCell cell = board.getCell(propertyId);
if (cell.type == CellType.PROPERTY || cell.type == CellType.STATION || cell.type == CellType.UTILITY) {
cell.owner = 0;
board.addMoney(0, -cell.price); // 扣除购买成本
}
int[] visits = simulator.simulate(board);
// 计算本局地产带来的租金总收入
long rentalIncome = 0;
for (int p = 1; p < 4; p++) {
// 统计其他玩家踩中次数 * 租金
// 简化:用visitCount近似
}
// 更直接的方式:模拟结束后看0号玩家资金
totalProfit += board.getPlayerMoney(0);
}
return (double) totalProfit / simulations;
}
/**
* 评估所有地产的期望被踩中频率
* 这是更基础的评估指标,不依赖具体购买策略
*/
double[] evaluateVisitFrequency() {
double[] freq = new double[MonopolyBoard.BOARD_SIZE];
GameSimulator freqSim = new GameSimulator(4, 200, 12345);
for (int sim = 0; sim < simulations; sim++) {
MonopolyBoard board = new MonopolyBoard(4);
// 每次使用不同随机种子
freqSim = new GameSimulator(4, 200, 12345L + sim);
int[] visits = freqSim.simulate(board);
for (int i = 0; i < MonopolyBoard.BOARD_SIZE; i++) {
freq[i] += visits[i];
}
}
// 归一化
double total = 0;
for (double v : freq) total += v;
for (int i = 0; i < freq.length; i++) {
freq[i] /= total;
}
return freq;
}
}
四、核心算法三:动态规划买地决策
4.1 决策建模
玩家到达一块无人地产时,需要决定是否购买。最优决策应考虑:
– 当前资金是否充裕
– 地产的期望回报周期
– 剩余对手资金状态
– 同色集齐潜力(垄断加成)
4.2 回报周期计算
/**
* 买地决策引擎
* 结合马尔可夫概率与蒙特卡洛频率做出最优决策
*/
class BuyDecisionEngine {
private final MarkovChain markov;
private final double[] visitFreq;
BuyDecisionEngine(double[] visitFreq) {
this.markov = new MarkovChain(MonopolyBoard.BOARD_SIZE);
this.visitFreq = visitFreq;
}
/**
* 计算地产的预期回报周期(回合数)
* @param cell 目标地产
* @param playerCount 玩家数
* @return 预期多少回合收回成本
*/
double paybackRounds(BoardCell cell, int playerCount) {
if (cell.type != CellType.PROPERTY && cell.type != CellType.STATION) {
return Double.MAX_VALUE;
}
// 预期每回合被踩中概率 = visitFreq * (playerCount - 1)
double expectedVisitsPerRound = visitFreq[cell.id] * (playerCount - 1);
if (expectedVisitsPerRound < 1e-9) return Double.MAX_VALUE;
double expectedIncomePerRound = expectedVisitsPerRound * cell.baseRent;
return cell.price / expectedIncomePerRound;
}
/**
* 综合评分决策
* @param cell 目标地产
* @param currentMoney 当前资金
* @param playerCount 总玩家数
* @param ownedInColorGroup 同色组已拥有数量
* @param totalInColorGroup 同色组总数量
* @return 评分(越高越值得买)
*/
double scorePurchase(BoardCell cell, int currentMoney, int playerCount,
int ownedInColorGroup, int totalInColorGroup) {
if (cell.type != CellType.PROPERTY && cell.type != CellType.STATION
&& cell.type != CellType.UTILITY) {
return Double.NEGATIVE_INFINITY;
}
if (currentMoney < cell.price) return Double.NEGATIVE_INFINITY;
double score = 0;
// 基础回报周期评分(周期越短越好)
double payback = paybackRounds(cell, playerCount);
score += 1000.0 / (payback + 10);
// 垄断潜力加成(同色组快集齐时大幅提升价值)
double monopolyBonus = 1.0;
if (ownedInColorGroup > 0) {
monopolyBonus = 1.0 + (ownedInColorGroup / (double) totalInColorGroup) * 2.0;
}
score *= monopolyBonus;
// 资金安全边际:保留至少30%资金用于应急
double safetyRatio = currentMoney / (double) cell.price;
if (safetyRatio < 1.5) {
score *= (safetyRatio - 1.0) / 0.5; // 资金紧张时降低评分
}
// 车站特殊处理:拥有多个车站时租金递增
if (cell.type == CellType.STATION) {
score *= 1.2;
}
return score;
}
/**
* 是否购买决策
* @param threshold 评分阈值,超过则购买
*/
boolean shouldBuy(BoardCell cell, int currentMoney, int playerCount,
int ownedInColorGroup, int totalInColorGroup, double threshold) {
double score = scorePurchase(cell, currentMoney, playerCount, ownedInColorGroup, totalInColorGroup);
return score >= threshold;
}
}
五、完整运行示例
public class MonopolyAI {
public static void main(String[] args) {
System.out.println("=== 大富翁AI决策系统 ===\n");
// 1. 验证骰子概率分布
DiceProbability.printDistribution();
// 2. 构建马尔可夫链并计算稳态分布
System.out.println("\n=== 稳态分布(长期被踩频率Top 10) ===");
MarkovChain chain = new MarkovChain(MonopolyBoard.BOARD_SIZE);
double[] steady = chain.stationaryDistribution(200);
// 排序输出频率最高的格子
Integer[] indices = new Integer[MonopolyBoard.BOARD_SIZE];
for (int i = 0; i < indices.length; i++) indices[i] = i;
Arrays.sort(indices, (a, b) -> Double.compare(steady[b], steady[a]));
MonopolyBoard demoBoard = new MonopolyBoard(4);
for (int i = 0; i < 10; i++) {
int idx = indices[i];
System.out.printf("%s: %.4f%n", demoBoard.getCell(idx).name, steady[idx]);
}
// 3. 蒙特卡洛模拟评估地产价值
System.out.println("\n=== 蒙特卡洛地产估值 ===");
PropertyEvaluator evaluator = new PropertyEvaluator(500);
double[] freq = evaluator.evaluateVisitFrequency();
BuyDecisionEngine engine = new BuyDecisionEngine(freq);
for (int i = 0; i < MonopolyBoard.BOARD_SIZE; i++) {
BoardCell cell = demoBoard.getCell(i);
if (cell.type == CellType.PROPERTY || cell.type == CellType.STATION) {
double payback = engine.paybackRounds(cell, 4);
double score = engine.scorePurchase(cell, 15000, 4, 0, 3);
System.out.printf("%s: 价格=%d, 回报周期=%.1f回合, 购买评分=%.2f%n",
cell.name, cell.price, payback, score);
}
}
// 4. 买地决策演示
System.out.println("\n=== 买地决策演示 ===");
BoardCell testCell = demoBoard.getCell(39); // 香港路,最贵地产
boolean buy = engine.shouldBuy(testCell, 15000, 4, 0, 2, 5.0);
System.out.printf("资金15000,到达%s(%d元): %s%n",
testCell.name, testCell.price, buy ? "购买" : "放弃");
BoardCell testCell2 = demoBoard.getCell(1); // 北京路,便宜地产
boolean buy2 = engine.shouldBuy(testCell2, 15000, 4, 0, 2, 5.0);
System.out.printf("资金15000,到达%s(%d元): %s%n",
testCell2.name, testCell2.price, buy2 ? "购买" : "放弃");
// 5. 多步转移概率演示
System.out.println("\n=== 从起点出发10步后到达各位置的概率Top 5 ===");
double[] prob10 = chain.nStepProbability(0, 10);
Integer[] probIdx = new Integer[MonopolyBoard.BOARD_SIZE];
for (int i = 0; i < probIdx.length; i++) probIdx[i] = i;
Arrays.sort(probIdx, (a, b) -> Double.compare(prob[b], prob[a]));
for (int i = 0; i < 5; i++) {
System.out.printf("%s: %.4f%n", demoBoard.getCell(probIdx[i]).name, prob10[probIdx[i]]);
}
}
}
六、复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 单步转移概率 | O(1) |
O(n) |
n为棋盘格子数 |
| 转移矩阵构建 | O(n^2) |
O(n^2) |
每对节点计算概率 |
| N步转移(快速幂) | O(n^3 * logN) |
O(n^2) |
矩阵快速幂 |
| 稳态分布迭代 | O(k * n^2) |
O(n) |
k为迭代次数 |
| 单局模拟 | O(r * p) |
O(n) |
r回合数,p玩家数 |
| 蒙特卡洛估值 | O(s * r * p) |
O(n) |
s为模拟次数 |
| 买地决策评分 | O(1) |
O(1) |
查表计算 |
其中 n = 40(标准棋盘大小),实际运行中矩阵快速幂和蒙特卡洛模拟是主要开销。
七、延伸优化方向
- 房屋建造策略:集齐全色地产后,使用动态规划决策建屋顺序,优先在对手到达概率高的地产上建房。
- 交易谈判算法:将地产交易建模为讨价还价博弈,使用纳什均衡计算最优交换方案。
- 囚犯困境建模:监狱停留策略(支付罚金立即出狱 vs 等待掷出 doubles)的期望收益比较。
- 对手建模:通过观察对手历史行为,更新其对不同地产的估值偏好,针对性制定竞争策略。
- GPU并行模拟:蒙特卡洛部分可完全并行化,使用多线程或GPU将模拟次数提升至百万级,显著提升估值精度。
八、总结
本文通过Java实现了大富翁的核心AI决策引擎,重点展示了四个算法要点:
- 图论建模将环形地图抽象为有向图,为后续概率计算奠定基础。
- 马尔可夫链精确刻画了掷骰移动的随机过程,矩阵快速幂高效计算多步转移概率。
- 蒙特卡洛模拟通过大量随机对局统计地产真实价值,弥补了纯理论模型的局限性。
- 动态规划评分综合回报周期、垄断潜力与资金安全,实现了可量化的买地决策。
大富翁将概率论、图论与博弈论融于一套规则中,是理解随机过程与决策优化的绝佳案例。