1 条题解

  • 0
    @ 2025-10-26 23:17:21

    题解:回合制战斗模拟

    题目分析

    这是一个复杂的回合制战斗模拟问题,需要严格按照给定的规则实现:

    • 两个队伍(南队和北队)进行回合制战斗
    • 每个角色有丰富的属性和技能系统
    • 三种攻击方式:普通攻击、特殊攻击、主动技能
    • 复杂的伤害计算体系,涉及多种加成
    • 需要处理状态变化、技能效果、战斗顺序等

    核心难点

    1. 数据结构设计:需要合理设计角色、队伍、技能效果等数据结构
    2. 伤害计算:涉及多层乘法关系和取整规则
    3. 状态管理:技能效果、回合计数、角色状态等
    4. 输出顺序:严格按照要求的时序输出信息

    算法设计

    1. 数据结构

    struct Character {
        string type;           // 种族
        int level;             // 等级
        int maxhp;             // 体力上限
        double atk;            // 基础攻击指数
        double def;            // 基础防御指数
        int skillLv;           // 主动技能等级
        int passiveSklLv;      // 被动技能等级
        string weaponType;     // 武器类型
        double weaponAtk;      // 武器攻击力
        
        int curhp;             // 当前体力值
        double skillBonus;     // 技能加成
        bool alive;            // 是否存活
    };
    
    struct Team {
        string name;           // "South" 或 "North"
        map<int, Character> members;  // 编号 -> 角色
        double attackBonus;    // 队伍攻击加成
        double defenseBonus;   // 队伍防御加成
        int lastActor;         // 上一个行动者编号
    };
    
    struct SkillEffect {
        int targetId;          // 目标编号
        string team;           // 目标队伍
        int remainingTurns;    // 剩余回合数
        int damagePerTurn;     // 每回合伤害
    };
    

    2. 伤害计算流程

    int calculateDamage(Character& attacker, Character& target, 
                       double baseMultiplier, int atkPos, int ddgPos) {
        // 1. 基础攻击强度
        double baseAtkStrength = attacker.atk * attacker.weaponAtk * baseMultiplier;
        
        // 2. 技能加成
        double skillBonus = attacker.skillBonus;
        
        // 3. 队伍攻击加成
        double teamAtkBonus = getTeamAttackBonus(attacker);
        
        // 4. 种族克制加成
        double raceBonus = getRaceBonus(attacker.type, target.type);
        
        // 5. 方位加成
        double positionBonus = getPositionBonus(atkPos, ddgPos);
        
        // 6. 计算攻击强度
        double attackStrength = baseAtkStrength * skillBonus * teamAtkBonus 
                              * raceBonus * positionBonus;
        
        // 7. 计算防御指数
        double defenseIndex = target.def * getTeamDefenseBonus(target);
        
        // 8. 计算伤害
        int damage = floor(attackStrength / defenseIndex);
        
        return damage;
    }
    

    3. 主循环结构

    vector<SkillEffect> skillEffects;  // 存储Average技能的持续效果
    
    for (int turn = 1; turn <= T; turn++) {
        // 确定当前行动者和队伍
        Team& currentTeam = (turn % 2 == 1) ? southTeam : northTeam;
        int actorId = determineActor(currentTeam, turn);
        
        // 回合开始:Weak被动技能治疗
        applyWeakPassiveSkill(currentTeam);
        
        // 解析行动
        Action action = parseAction(input);
        
        // 执行行动
        if (action.type == "Skill") {
            applyActiveSkill(currentTeam, actorId, action);
        } else if (action.type == "Basicattack" || action.type == "Specialattack") {
            applyAttack(currentTeam, actorId, action);
        }
        
        // 回合结束:Average技能伤害
        applyAverageSkillEffects();
        
        // 更新技能效果剩余回合
        updateSkillEffects();
        
        // 输出队伍状态
        printTeamStatus();
        
        // 检查胜利条件
        if (checkVictory()) break;
    }
    

    4. 关键函数实现

    确定行动者

    int determineActor(Team& team, int turn) {
        if (turn <= 2) {
            // 前两回合选择编号最小的存活者
            return findMinAliveId(team);
        } else {
            // 找比上一个行动者编号大的最小存活者
            int candidate = findNextAliveId(team, team.lastActor);
            if (candidate == -1) {
                // 没有更大的,回到最小的
                candidate = findMinAliveId(team);
            }
            team.lastActor = candidate;
            return candidate;
        }
    }
    

    特殊攻击处理

    void handleSpecialAttack(Team& attackerTeam, int attackerId, Action& action) {
        Character& attacker = attackerTeam.members[attackerId];
        Team& targetTeam = (attackerTeam.name == "South") ? northTeam : southTeam;
        
        vector<int> targets = getSpecialAttackTargets(targetTeam, action.target);
        
        for (int targetId : targets) {
            Character& target = targetTeam.members[targetId];
            double multiplier = getSpecialAttackMultiplier(attacker.weaponType, targets.size());
            
            int damage = calculateDamage(attacker, target, multiplier, 
                                       action.atkPos, action.ddgPos);
            
            applyDamage(targetTeam, targetId, damage, attackerTeam.name, attackerId);
            
            // 检查目标是否倒下
            if (target.curhp <= 0) {
                target.alive = false;
            }
        }
        
        // 攻击后重置技能加成
        attacker.skillBonus = 1.0;
    }
    

    实现细节

    1. 浮点数处理

    由于题目使用特殊格式(如 15588e-4),需要正确解析:

    double parseScientific(string str) {
        size_t e_pos = str.find('e');
        if (e_pos == string::npos) return stod(str);
        
        double mag = stod(str.substr(0, e_pos));
        int exp = stoi(str.substr(e_pos + 1));
        return mag * pow(10, exp);
    }
    

    2. 取整规则

    所有涉及比例的计算都需要下取整:

    int calculateHeal(Character& target, double percentage) {
        return floor(target.maxhp * percentage);
    }
    

    3. 状态更新顺序

    严格按照题目要求的顺序:

    1. Weak被动技能治疗(回合开始)
    2. 主动技能应用
    3. 攻击伤害计算
    4. Average技能伤害(回合结束)

    4. 输出格式控制

    注意方括号的使用和空格要求:

    void printTeamStatus(Team& team) {
        vector<int> order = {5, 3, 1, 2, 4, 6};
        cout << team.name << ": ";
        
        bool first = true;
        for (int id : order) {
            if (team.members.count(id)) {
                if (!first) cout << " ";
                Character& c = team.members[id];
                if (id == 1) {
                    cout << c.curhp << "/" << c.maxhp;
                } else {
                    cout << "[" << c.curhp << "/" << c.maxhp << "]";
                }
                first = false;
            }
        }
        cout << endl;
    }
    

    复杂度分析

    • 时间复杂度O(T×N)O(T \times N),其中 TT 是回合数,NN 是队伍人数
    • 空间复杂度O(N+E)O(N + E),其中 EE 是同时存在的技能效果数量

    在数据范围 T50000,N12T \le 50000, N \le 12 的情况下完全可行。


    调试技巧

    1. 分模块测试:先实现伤害计算,验证正确性
    2. 边界情况:测试伤害为0、治疗溢出、技能覆盖等情况
    3. 样例验证:用题目样例逐步调试
    4. 输出中间结果:在关键步骤输出调试信息

    总结

    本题是一个典型的大模拟题,考察:

    • 复杂规则的理解和实现能力
    • 数据结构设计和状态管理
    • 细节处理和边界情况考虑
    • 代码组织和调试能力

    关键成功因素

    1. 仔细阅读题目,理解所有规则细节
    2. 合理设计数据结构,避免重复计算
    3. 严格按照时间顺序处理各种效果
    4. 注意浮点数精度和取整规则

    虽然规则复杂,但通过模块化设计和逐步实现,可以完成这个挑战性的模拟题目。

    • 1

    信息

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