ACM真题讲解——“Darkterror‘s Combos”

ACM真题讲解——“Darkterror's Combos”

引言

在众多算法竞赛中,Dota-Allstars的英雄们以其独特的技能组合为题目提供了丰富的想象空间。本次我们要深入探讨的是一道结合了游戏元素和算法设计的ACM真题——“Darkterror's Combos”。

题目背景

题目围绕Dota-Allstars中的英雄Darkterror(虚空假面)展开。Darkterror以其时间漫游和时间结界技能而闻名。时间结界能够在以自身为中心的圆形区域内,冻结所有范围内的敌方英雄。

题目描述

给定多个英雄的位置和威胁等级,你需要计算Darkterror使用时间结界技能时,能够覆盖的最大威胁等级总和。每个英雄的位置由二维坐标系中的点(x, y)表示,威胁等级由整数l表示。

输入输出格式

  • 输入:包含三个整数Rw, Rc, R,分别代表时间结界的有效半径、搜索半径以及技能影响半径。
  • 输入:接下来是n个整数对(x, y)和对应的威胁等级l,表示英雄的位置和威胁等级。
  • 输出:一个整数,表示通过合理选择时间结界的释放点,能够达到的最大威胁等级总和。

问题分析

本题的关键在于如何确定时间结界的释放点,以覆盖尽可能多的高威胁等级英雄。问题可以转化为寻找一个圆心,使得该圆与尽可能多的以英雄为圆心的半径为R的圆相交。

算法选择

考虑到问题的本质是几何问题,我们可以使用几何算法来解决。一种可能的方法是枚举所有可能的圆心,然后计算每个圆心能够覆盖的威胁等级总和。

算法逻辑

  1. 枚举圆心:遍历所有可能的圆心位置,这些位置可以是每个英雄的位置或者英雄位置的整数倍。
  2. 计算覆盖:对于每个圆心,检查以R为半径的圆能够覆盖哪些英雄。
  3. 累加威胁等级:对于每个圆心,累加其覆盖范围内所有英雄的威胁等级。
  4. 更新最大值:比较当前圆心的威胁等级总和与已知的最大值,更新最大值。

代码实现(天啦噜!!!)

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <limits>

using namespace std;

struct Point {
    int x, y;
};

struct Circle {
    Point center;
    int radius;
};

// 计算两个圆是否相交,并返回相交区域的矩形边界
bool calculateIntersection(const Circle& c1, const Circle& c2, Point& leftBottom, Point& rightTop) {
    double dx = c1.center.x - c2.center.x;
    double dy = c1.center.y - c2.center.y;
    double distance = sqrt(dx * dx + dy * dy);

    if (distance > c1.radius + c2.radius) {
        // 圆不相交
        return false;
    }

    // 计算相交区域的中心点
    int intersectionCenterX = (c1.center.x + dx * c2.radius / distance) / 2;
    int intersectionCenterY = (c1.center.y + dy * c2.radius / distance) / 2;

    // 计算相交区域的宽度和高度
    int width = int(fabs((c1.radius * c1.radius - (distance * distance - c2.radius * c2.radius)) / (2 * distance)));
    int height = int(fabs((c2.radius * c2.radius - (distance * distance - c1.radius * c1.radius)) / (2 * distance)));

    leftBottom.x = intersectionCenterX - width;
    leftBottom.y = intersectionCenterY - height;
    rightTop.x = intersectionCenterX + width;
    rightTop.y = intersectionCenterY + height;

    return true;
}

// 检查点是否在多圆交集区域内
bool isInsideIntersectArea(const Point& point, const vector<Circle>& circles) {
    // 初始为第一个圆的边界
    Point leftBottom, rightTop;
    if (!calculateIntersection(circles[0], circles[1], leftBottom, rightTop)) {
        return false;
    }

    // 与剩余的圆计算交集
    for (size_t i = 2; i < circles.size(); ++i) {
        Circle intersectCircle;
        if (!calculateIntersection(Circle{leftBottom, (rightTop.x - leftBottom.x) + (rightTop.y - leftBottom.y)}, circles[i], leftBottom, rightTop)) {
            return false;
        }
    }

    // 检查点是否在最终的交集区域内
    return point.x >= leftBottom.x && point.x <= rightTop.x &&
           point.y >= leftBottom.y && point.y <= rightTop.y;
}

// 计算最大威胁等级总和
int calculateMaxThreat(const vector<Point>& heroes, const vector<int>& threats, vector<Circle>& circles) {
    int maxThreat = numeric_limits<int>::min();
    int n = heroes.size();

    // 枚举交集区域中的所有点
    for (int x = -1000000; x <= 1000000; x++) {
        for (int y = -1000000; y <= 1000000; y++) {
            if (isInsideIntersectArea({x, y}, circles)) {
                int currentThreat = 0;
                for (int i = 0; i < n; i++) {
                    // 计算威胁等级
                    if (hypot(heroes[i].x - x, heroes[i].y - y) <= circles[i].radius) {
                        currentThreat += threats[i];
                    }
                }
                maxThreat = max(maxThreat, currentThreat);
            }
        }
    }

    return maxThreat;
}

int main() {
    int n, Rw, Rc, R;
    cin >> n >> Rw >> Rc >> R;

    vector<Point> heroes(n);
    vector<int> threats(n);
    vector<Circle> circles(n);

    for (int i = 0; i < n; i++) {
        cin >> heroes[i].x >> heroes[i].y >> threats[i];
        circles[i] = {heroes[i], R};
    }

    int maxThreat = calculateMaxThreat(heroes, threats, circles);
    cout << "Maximum threat sum: " << maxThreat << endl;

    return 0;
}

结论

“Darkterror's Combos” 是一道结合了游戏元素和几何算法的有趣题目。通过对问题的深入分析和合理的算法设计,我们能够有效地解决这一问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值