news 2026/4/16 21:41:00

UVa 149 Forests

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVa 149 Forests

题目分析

这道题来源于一个常见的观察现象:在森林中,当你站在某个位置观察时,远处的树木可能会被近处的树木遮挡,导致你无法看清远处的树木。题目中给出了一个数学模型:树木被抽象为直径相同的圆柱体,它们的中心位于一个单位间距的无限矩形网格上。观察者站在某个坐标点( x , y ) (x, y)(x,y)上,用一只眼睛观察。只有当一棵树在观察者眼中所张的视角大于0.01 0.010.01度,并且它的树干没有被更近的树木遮挡时,这棵树才是可见的。

关键点:

  • 树木直径d dd满足0.1 ≤ d ≤ x , y ≤ 1 − d 0.1 \le d \le x, y \le 1-d0.1dx,y1d
  • 网格是无限的,但题目通过坐标缩放保证了输入坐标在[ 0 , 1 ] [0,1][0,1]之间。
  • 需要计算从给定观察点可以看到的树木数量。

解题思路

由于网格是无限的,直接枚举所有树木是不可能的。我们需要找到一种有效的方法来判断哪些树是可见的。

1. 几何模型

每棵树是一个直径为d dd的圆柱体。观察者位于O ( x , y ) O(x, y)O(x,y),树木中心位于网格点T ( i , j ) T(i, j)T(i,j)。要判断T TT是否可见,需要考虑:

  • 视角大小:树木在观察者眼中的张角必须大于0.01 0.010.01度。
  • 遮挡关系:如果存在另一棵树N NNT TT更接近观察者,并且从O OOT TT的视线被N NN的树干遮挡,那么T TT不可见。

2. 遮挡判定

对于两棵树N NN(近)和F FF(远),我们需要判断N NN是否遮挡了F FF。这可以通过计算角度来判断:
设:

  • a = ∣ O N ∣ 2 a = |ON|^2a=ON2
  • b = ∣ O F ∣ 2 b = |OF|^2b=OF2
  • c = ∣ N F ∣ 2 c = |NF|^2c=NF2
  • A = arcsin ⁡ ( d / ( 2 a ) ) A = \arcsin(d / (2\sqrt{a}))A=arcsin(d/(2a))N NN树干的半张角)
  • B = arcsin ⁡ ( d / ( 2 b ) ) B = \arcsin(d / (2\sqrt{b}))B=arcsin(d/(2b))F FF树干的半张角)
  • cos ⁡ C = ( a + b − c ) / ( 2 a b ) \cos C = (a + b - c) / (2\sqrt{a}\sqrt{b})cosC=(a+bc)/(2ab)C = arccos ⁡ ( cos ⁡ C ) C = \arccos(\cos C)C=arccos(cosC)O OO到两棵树中心的夹角)

如果C − A − B ≤ 0.01 C - A - B \le 0.01CAB0.01度(转换为弧度比较),则N NN遮挡了F FF

3. 枚举范围

由于网格无限,但树木大小固定,观察点位置有限,实际上只需要检查一定范围内的树木即可:

  • 将坐标乘以100 100100转换为整数网格,便于计算。
  • 将平面分为四个象限,每个象限内按“深度”(距离观察点的网格层数)逐步向外检查。
  • 对于每一层,检查该层的角点和边上的树木是否可见。
  • 设置最大深度为10 1010,这足以覆盖所有可能可见的树木。

4. 实现细节

  • 使用isObscured函数判断两棵树之间的遮挡关系。
  • 使用isVisible函数判断一棵树是否被当前层内的任何更近的树遮挡。
  • 主函数循环读取输入,对每个测试用例调用visibleTrees计算可见树木数量并输出。

代码实现

// Forests// UVa ID: 149// Verdict: Accepted// Submission Date: 2016-02-01// UVa Run Time: 0.000s//// 版权所有(C)2016,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;constdoublePI=3.14159265358;structpoint{doublex,y;};doublediameter,x,y;point base[4]={{100,100},{0,100},{0,0},{100,0}};intsteps[4][2]={{100,100},{-100,100},{-100,-100},{100,-100}};intsubSteps[8][2]={{-100,0},{0,-100},{100,0},{0,-100},{100,0},{0,100},{-100,0},{0,100}};doublemaxCos=cos(0.01/180*PI);boolisObscured(point near,point far){doublea=pow(x-near.x,2)+pow(y-near.y,2);doubleb=pow(x-far.x,2)+pow(y-far.y,2);doublec=pow(near.x-far.x,2)+pow(near.y-far.y,2);doubleA=asin(diameter/2/sqrt(a));doubleB=asin(diameter/2/sqrt(b));doublecosC=(a+b-c)/(2*sqrt(a)*sqrt(b));// 因为余弦的值域为[-1, 1],故绝对值大于 1 的值取反余弦会得到一个非数值(NAN),// 而且题目中提到当角度大于 0.01 度时人眼才能区分,因此需要设定一个阈值。// 此处是关键,否则很可能 Wrong Answer。if(cosC>=maxCos)returntrue;doubleC=acos(cosC);return((C-A-B)*180/PI)<=0.01f;}boolisVisible(point tree,intdepth,intquadrant){for(intsubDepth=0;subDepth<depth;subDepth++){point corner={base[quadrant].x+subDepth*steps[quadrant][0],base[quadrant].y+subDepth*steps[quadrant][1]};if(isObscured(corner,tree))returnfalse;for(intj=2*quadrant;j<2*(quadrant+1);j++)for(intk=0;k<subDepth;k++){point vertex={corner.x+subSteps[j][0]*(k+1),corner.y+subSteps[j][1]*(k+1)};if(isObscured(vertex,tree))returnfalse;}}returntrue;}intvisibleTrees(){intcount=0;for(intdepth=0;depth<=10;depth++)for(inti=0;i<4;i++){point corner={base[i].x+depth*steps[i][0],base[i].y+depth*steps[i][1]};if(isVisible(corner,depth,i))count++;for(intj=2*i;j<2*(i+1);j++)for(intk=0;k<depth;k++){point tree={corner.x+subSteps[j][0]*(k+1),corner.y+subSteps[j][1]*(k+1)};if(isVisible(tree,depth,i))count++;}}returncount;}intmain(){while(cin>>diameter>>x>>y){diameter=(int)(diameter*100);x=(int)(x*100),y=(int)(y*100);if(diameter==0&&x==0&&y==0)break;cout<<visibleTrees()<<endl;}return0;}

总结

本题的关键在于将无限网格问题转化为有限范围内的几何遮挡判断。通过合理的枚举顺序和角度计算,可以在有限时间内得到正确结果。代码中使用了整数运算以提高精度和效率,同时注意处理了角度比较的边界情况,避免了因浮点误差导致的错误。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:14:19

实时数据处理引擎优化实战指南:从瓶颈诊断到毫秒级响应

实时数据处理引擎优化实战指南&#xff1a;从瓶颈诊断到毫秒级响应 【免费下载链接】Indicator 通达信缠论可视化分析插件 项目地址: https://gitcode.com/gh_mirrors/ind/Indicator [阶段一] 问题诊断&#xff1a;实时数据处理延迟危机 核心矛盾&#xff1a;数据洪峰下…

作者头像 李华
网站建设 2026/4/16 18:17:59

揭秘Gaggiuino 616ea70:5大升级让家用咖啡机秒变专业设备

揭秘Gaggiuino 616ea70&#xff1a;5大升级让家用咖啡机秒变专业设备 【免费下载链接】gaggiuino A Gaggia Classic control project using microcontrollers. 项目地址: https://gitcode.com/gh_mirrors/ga/gaggiuino &#x1f680; 项目亮点&#xff1a;重新定义家用咖…

作者头像 李华
网站建设 2026/4/16 13:01:32

RMBG-1.4快速接入指南:避免环境冲突的部署方法

RMBG-1.4快速接入指南&#xff1a;避免环境冲突的部署方法 1. 为什么需要“不踩坑”的RMBG-1.4部署方式&#xff1f; 你可能已经试过在本地跑RMBG-1.4——下载模型、装PyTorch、配CUDA版本、解决torchvision兼容性报错……最后卡在ImportError: cannot import name MultiScal…

作者头像 李华
网站建设 2026/4/16 14:28:17

GLM-4.7-Flash开发者案例:VS Code插件集成GLM-4.7-Flash辅助编程

GLM-4.7-Flash开发者案例&#xff1a;VS Code插件集成GLM-4.7-Flash辅助编程 你是否试过在写代码时卡在某个函数调用上&#xff0c;翻文档、查Stack Overflow、反复调试&#xff0c;一晃半小时过去了&#xff1f;或者刚接手一个陌生项目&#xff0c;面对几千行没有注释的Pytho…

作者头像 李华
网站建设 2026/4/16 14:02:51

探索群晖NAS网络升级实战:USB网卡驱动完全指南

探索群晖NAS网络升级实战&#xff1a;USB网卡驱动完全指南 【免费下载链接】r8152 Synology DSM driver for Realtek RTL8152/RTL8153/RTL8156 based adapters 项目地址: https://gitcode.com/gh_mirrors/r8/r8152 在NAS存储方案中&#xff0c;网络性能往往成为数据传输…

作者头像 李华
网站建设 2026/4/16 14:02:30

Qwen3-VL应急管理应用:灾情图像快速研判实战

Qwen3-VL应急管理应用&#xff1a;灾情图像快速研判实战 1. 为什么灾情研判急需一个“看得懂图、说得清事”的AI&#xff1f; 你有没有想过&#xff0c;当地震、山洪或火灾发生后&#xff0c;一线人员传回的第一批现场图片&#xff0c;往往只有几十秒的黄金研判时间&#xff…

作者头像 李华