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的圆相交。
算法选择
考虑到问题的本质是几何问题,我们可以使用几何算法来解决。一种可能的方法是枚举所有可能的圆心,然后计算每个圆心能够覆盖的威胁等级总和。
算法逻辑
- 枚举圆心:遍历所有可能的圆心位置,这些位置可以是每个英雄的位置或者英雄位置的整数倍。
- 计算覆盖:对于每个圆心,检查以R为半径的圆能够覆盖哪些英雄。
- 累加威胁等级:对于每个圆心,累加其覆盖范围内所有英雄的威胁等级。
- 更新最大值:比较当前圆心的威胁等级总和与已知的最大值,更新最大值。
代码实现(天啦噜!!!)
#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” 是一道结合了游戏元素和几何算法的有趣题目。通过对问题的深入分析和合理的算法设计,我们能够有效地解决这一问题。