1 条题解

  • 0
    @ 2025-10-29 21:53:59

    题目分析
    本题要求模拟一个复杂的消消乐游戏,包含多种特殊效果和计分规则。需要准确处理交换、消除、下落、连锁反应和多种计分方式。


    算法思路

    核心思想:模拟 + 搜索

    主要流程

    1. 检查操作有效性
    2. 处理消除和连锁反应
    3. 计算各类奖分
    4. 更新棋盘状态

    算法流程详解

    1. 操作有效性检查

    bool chk(int x, int y, int xx, int yy) {
        // 检查相邻、非空、交换后能形成三连
        swap(mp[x][y], mp[xx][yy]);
        if (!tri()) {
            swap(mp[x][y], mp[xx][yy]);
            return 0;
        }
        return 1;
    }
    

    2. 主颜色记录

    void gmaincol(int x, int y, int xx, int yy) {
        // 记录通过直接交换被消除的颜色
        if (clr[x][y]) lst[cnt].emplace_back(mp[x][y].a);
        if (clr[xx][yy]) lst[cnt].emplace_back(mp[xx][yy].a);
    }
    

    3. 消除检测与处理

    基础三连检测

    bool ctri() {
        // 检测行和列的三连
        for (int i = 1; i < n - 1; i++)
            for (int j = 1; j <= m; j++)
                if (mp[i][j].a && mp[i][j].a == mp[i+1][j].a && ...)
                    clr[i][j] = clr[i+1][j] = clr[i+2][j] = 1;
        // 类似处理列
    }
    

    特殊效果传播

    bool gspch() {
        // 处理特殊效果的连锁触发
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                if (clr[i][j] && mp[i][j].b && !upded[i][j]) {
                    upded[i][j] = 1;
                    colsp(i, j, mp[i][j].b); // 触发特殊效果
                }
            }
    }
    

    4. 计分系统

    消除奖分

    void Sakuzyo() {
        int sum = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                if (clr[i][j]) sum += mp[i][j].a;
        scr += sum * rnd; // 第r轮消除
    }
    

    组合奖分

    void scupd() {
        // DFS计算连通块大小
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                if (clr[i][j] && !vis[i][j]) {
                    trcnt = 0;
                    dfs(i, j, mp[i][j].a);
                    scr += 50 * (trcnt - 3) * (trcnt - 3);
                }
            }
    }
    

    牌型奖分

    // 枚举最近5次操作的主颜色组合
    for (auto v1 : lst[cnt-4]) for (auto v2 : lst[cnt-3]) ... {
        map<int, int> mp; // 统计颜色出现次数
        // 根据牌型规则计算奖分
        if (mp.size() == 5) nscr += 50 + max_color; // 高牌
        else if (mp.size() == 4) nscr += 100 + pair_color; // 一对
        // ... 其他牌型
    }
    

    5. 重力下落

    void falldown() {
        for (int i = n; i >= 1; i--)
            for (int j = 1; j <= m; j++) {
                if (mp[i][j].a) {
                    int pos = i;
                    while (pos < n && !mp[pos+1][j].a) ++pos;
                    swap(mp[i][j], mp[pos][j]);
                }
            }
    }
    

    关键技术与优化

    1. 连锁反应处理

    • 使用 upded 数组标记已触发的特殊效果,避免重复触发
    • 在单轮消除内完成所有特殊效果传播

    2. 状态标记

    • clr[][]:标记待消除的棋子
    • vis[][]:DFS访问标记
    • upded[][]:特殊效果触发标记

    3. 主颜色追踪

    • 只记录通过直接交换被消除的颜色
    • 保存最近5次操作的主颜色用于牌型计算

    4. 牌型枚举优化

    • 直接枚举所有可能的颜色组合
    • 由于数据范围小(最多2种主颜色×5次操作),暴力可行

    复杂度分析

    • 单次操作:最坏 O(n2m2)O(n^2m^2)(多次连锁消除)
    • 牌型计算O(25)=O(32)O(2^5) = O(32)
    • 总体O(qn2m2)O(q \cdot n^2m^2),对于 n,m50,q1000n,m \leq 50, q \leq 1000 可接受

    样例验证

    样例1

    • 5次有效操作
    • 计算消除奖分、连锁奖分、组合奖分
    • 第5次操作后计算牌型奖分:两对(1,2,4,2,4) → 210分
    • 终局奖分:1000 + 10000 = 11000
    • 总分:315+417+429+435+482 + 210 + 11000 = 11692

    样例2

    • 包含无效操作,失去终局奖分
    • 总分较低

    算法优势

    1. 逻辑完整:严格按题意实现所有规则
    2. 模块清晰:分离消除检测、特殊效果、计分等模块
    3. 边界处理:妥善处理各种边界情况
    4. 可扩展性:易于添加新的特殊效果或计分规则

    该算法通过系统的状态管理和模块化设计,完整实现了复杂的消消乐游戏逻辑。

    • 1

    信息

    ID
    4698
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者