当前位置: 首页 > news >正文

UVa 11853 Paintball

题目描述

你正在一个 1000×10001000 \times 10001000×1000 的正方形场地上玩彩弹游戏。场地上有若干对手躲在树后,每个对手位于 (x,y)(x, y)(x,y) 位置,并且可以朝任意方向发射彩弹,攻击范围为 rrr。如果你在移动过程中进入任何对手的攻击范围,就会被击中。

场地左下角为 (0,0)(0,0)(0,0),左上角为 (0,1000)(0,1000)(0,1000)。你必须从场地的左侧边(介于西南角和西北角之间)进入,从右侧边(介于东南角和东北角之间)离开。

对于每个场景,判断是否能完成穿越。如果能,输出进入点和离开点的坐标(保留两位小数),且要选择最北的入口;如果不能,输出 IMPOSSIBLE

输入格式

输入包含多个场景。每个场景的第一行是整数 n≤1000n \leq 1000n1000,表示对手数量。接下来 nnn 行,每行包含三个实数:对手的 (x,y)(x, y)(x,y) 坐标和攻击半径 rrr

输出格式

对于每个场景,输出四个实数(保留两位小数)表示进入和离开坐标,或者输出 IMPOSSIBLE

样例输入

3
500 500 499
0 0 999
1000 1000 200

样例输出

0.00 1000.00 1000.00 800.00

题目分析

问题本质

这是一个平面几何连通性问题:

  • 每个对手相当于一个圆形禁区(圆心 (x,y)(x, y)(x,y),半径 rrr
  • 我们需要判断是否存在一条从左边界到右边界的路径,全程不进入任何圆形禁区
  • 如果存在,还要找到最北的入口和出口

关键观察

  1. 屏障效应:如果存在一组相连的圆形成从上边界到下边界的连续屏障,则无法穿越
  2. 边界阻挡:即使没有完整屏障,某些圆可能阻挡左侧或右侧的特定区域,影响入口和出口的选择

解题思路

第一步:判断可行性(是否存在通路)

使用并查集Union-Find\texttt{Union-Find}Union-Find)来判断是否存在从上边界到下边界的连续屏障:

  1. 合并相交的圆:如果两个圆的圆心距离小于等于半径之和,它们相交,属于同一连通分量
  2. 标记边界接触
    • 如果一个圆与上边界y=1000y = 1000y=1000)相交或相切,标记该连通分量接触上边界
    • 如果一个圆与下边界y=0y = 0y=0)相交或相切,标记该连通分量接触下边界
  3. 检查屏障:如果存在某个连通分量同时接触上边界和下边界,则形成完整屏障,输出 IMPOSSIBLE

第二步:寻找最北入口和出口

使用 BFS\texttt{BFS}BFS(广度优先搜索)从接触上边界的圆开始扩展阻挡区域:

  1. 初始化:将所有接触上边界的圆加入队列
  2. BFS扩展:不断将与当前圆相交的未访问圆加入队列
  3. 更新边界阻挡
    • 对于每个访问到的圆,检查是否与左边界x=0x = 0x=0)相交
      • 如果相交,计算交点范围 [y−r2−x2,y+r2−x2][y - \sqrt{r^2 - x^2}, y + \sqrt{r^2 - x^2}][yr2x2,y+r2x2]
      • 更新左边界阻挡的最南端为这些交点范围的最小值
    • 同样检查是否与右边界x=1000x = 1000x=1000)相交
      • 如果相交,计算交点范围 [y−r2−(1000−x)2,y+r2−(1000−x)2][y - \sqrt{r^2 - (1000-x)^2}, y + \sqrt{r^2 - (1000-x)^2}][yr2(1000x)2,y+r2(1000x)2]
      • 更新右边界阻挡的最南端为这些交点范围的最小值
  4. 确定入口和出口
    • 最北入口 = 左边界阻挡的最南端(如果无阻挡则为 1000.001000.001000.00
    • 最北出口 = 右边界阻挡的最南端(如果无阻挡则为 1000.001000.001000.00

算法正确性证明

可行性判断

  • 如果存在连通分量同时接触上下边界,则这些圆形成连续屏障,无法穿越
  • 否则,至少存在一条通路可以穿越场地

最北入口确定

  • 所有接触上边界的圆及其相连圆构成顶部阻挡区域
  • 这个区域在左边界上的最南端点就是最北的安全入口
  • 因为任何比这个点更北的入口都会被顶部阻挡区域拦截

参考代码

// Paintball
// UVa ID: 11853
// Verdict: Accepted
// Submission Date: 2025-10-30
// UVa Run Time: 0.010s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include <bits/stdc++.h>using namespace std;const double eps = 1e-8;
const double W = 1000.0;struct Circle {double x, y, r;
};double dist(double x1, double y1, double x2, double y2) {return hypot(x1 - x2, y1 - y2);
}bool circlesIntersect(const Circle& a, const Circle& b) {return dist(a.x, a.y, b.x, b.y) < a.r + b.r + eps;
}int parent[1005];int find(int x) {if (parent[x] != x) parent[x] = find(parent[x]);return parent[x];
}void unite(int a, int b) {a = find(a);b = find(b);if (a != b) parent[a] = b;
}int main() {ios_base::sync_with_stdio(false);cin.tie(NULL);int n;while (cin >> n) {vector<Circle> enemies(n);for (int i = 0; i < n; i++) {cin >> enemies[i].x >> enemies[i].y >> enemies[i].r;}// ===== 第一步:用并查集判断是否存在通路 =====for (int i = 0; i < n; i++) parent[i] = i;// 合并相交的圆for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {if (circlesIntersect(enemies[i], enemies[j])) {unite(i, j);}}}// 检查每个连通分量是否同时接触上边界和下边界vector<bool> top(n, false), bottom(n, false);for (int i = 0; i < n; i++) {int root = find(i);if (enemies[i].y + enemies[i].r > W - eps) top[root] = true;if (enemies[i].y - enemies[i].r < eps) bottom[root] = true;}bool impossible = false;for (int i = 0; i < n; i++) {if (parent[i] == i && top[i] && bottom[i]) {impossible = true;break;}}if (impossible) {cout << "IMPOSSIBLE\n";continue;}// ===== 第二步:寻找最北入口和出口 =====vector<bool> visited(n, false);double leftBlock = W;  // 左边界阻挡的最南端,初始为最北double rightBlock = W; // 右边界阻挡的最南端,初始为最北// BFS 从接触上边界的圆开始扩展阻挡区域vector<int> queue;for (int i = 0; i < n; i++) {if (enemies[i].y + enemies[i].r > W - eps) { // 接触上边界visited[i] = true;queue.push_back(i);}}// BFS 扩展阻挡区域for (int idx = 0; idx < queue.size(); idx++) {int u = queue[idx];const Circle& c = enemies[u];// 更新左边界阻挡if (c.x - c.r < eps) { // 接触左边界double dy = sqrt(max(0.0, c.r * c.r - c.x * c.x)); // 避免数值误差double bottomY = c.y - dy;if (bottomY < leftBlock) {leftBlock = bottomY;}}// 更新右边界阻挡if (c.x + c.r > W - eps) { // 接触右边界double dx = W - c.x;double dy = sqrt(max(0.0, c.r * c.r - dx * dx)); // 避免数值误差double bottomY = c.y - dy;if (bottomY < rightBlock) {rightBlock = bottomY;}}// 扩展相邻圆for (int v = 0; v < n; v++) {if (!visited[v] && circlesIntersect(c, enemies[v])) {visited[v] = true;queue.push_back(v);}}}// 确定入口和出口坐标double enterY, exitY;if (leftBlock > W - eps) {// 没有圆阻挡左边界,入口可以是 (0, 1000)enterY = W;} else {// 阻挡区域最南端就是最北入口enterY = leftBlock;// 如果阻挡区域延伸到 y = 0 以下,入口只能是0if (enterY < 0) enterY = 0;}if (rightBlock > W - eps) {// 没有圆阻挡右边界,出口可以是 (1000, 1000)exitY = W;} else {// 阻挡区域最南端就是最北出口exitY = rightBlock;// 如果阻挡区域延伸到 y = 0 以下,出口只能是 0if (exitY < 0) exitY = 0;}// 输出结果cout << fixed << setprecision(2)<< 0.00 << " " << enterY << " "<< W << " " << exitY << "\n";}return 0;
}
http://www.dtcms.com/a/550690.html

相关文章:

  • 北京网站制作公司兴田德润在那里中国最新领导班子
  • 优秀网站seo报价wordpress亚马逊cdn
  • 韶关网站设计公司建设网站 请示 报告
  • 网站开发 兼职挣钱吗WordPress dux3.0
  • 建设网站和公告号的意义网上平台
  • 磁盘分区方案GPT和MBR的区别浅谈
  • 怎么用ps做网站首页字贵阳大数据论坛
  • php p2p网站源码网站icp备案申请流程
  • Java的Stream详解
  • 国家网站备案查询定制开发教程
  • MySQL安装及启用(社区版)
  • whois域名查询网站iis 添加网站 win7
  • 图像分割深度学习学习总结
  • 中铁建设集团网站能用VUE做网站
  • 网站超链接怎么做 word文档网页设计免费模板网站推荐
  • 网站支付接口怎么做百度站长怎么做网站维护
  • 查建筑材料的网站大数据系统
  • 建设银行 北京招聘网站网站代码 公告栏 php
  • leetcode3040.相同分数的最大操作数目II
  • dz网站标题公司做网站的费用用途写什么
  • 从局域网工具到全球传输:FastSend的无服务器共享革命
  • PostgreSQL 定位索引损坏位置
  • 做网站销售怎么找客户用群晖做网站服务器
  • 兰州做高端网站的公司查做外贸客户的网站
  • 打工人日报#20251030
  • 馆陶企业做网站推广构建网站需要会什么意思
  • H264的码流结构
  • 苏省住房和城乡建设厅网站首页平湖公司做网站
  • 网站购物车功能怎么做湘潭网站建设网站推广
  • go操作xml