zoukankan      html  css  js  c++  java
  • UVA

    /*
      这题的思路让我觉得很巧妙,所以...虽然小白书  P175 ,已经有详细到能看懂的解释了,但我还是用自己的话,把书上的解析复述一遍:
      
      简化:
      先判断解的存在性,有解再找解
      
      类比:
      可将敌人类比为圆,攻击范围则为一个个以敌人位置为圆心,攻击距离为半径的圆
      
      可将战场看成湖,敌人的攻击范围组成的圆,看作一个个圆形踏脚石,看能否从湖的上边界走到下边界
      
      分析:
      题意所求,就是想知道,能否从左边界到右边界,并找到最北进入点和最北出边界点
      
      可以先考虑一下,何时不可能从左边界走到右边界?
      答:在敌人攻击范围的圆,能够组成一个从上边界到下边界的连通块时,因为这是,战场相当于被( 一条从上边界到下边界到分界线 )分成了东西两块,分界线上,都是敌人的攻击区域所覆盖的范围,那么无论如何也没有办法走到右边界了
      
      至于最北位置,书上 P175 讲了判断方法,理解的层面,结合下集合和不等式的知识,想通不难,就不赘述了
      
      这题最关键的是类比思想的运用,以把它转换为我们熟悉的连通块问题
      
      值得一提的是:
      1. 这题在浮点数判相等时,讲道理是该用 EPS 判等,考虑浮点误差的。但这题好像没有想在这里卡我们,因为直接用 <= 时,居然也是可以 AC 的...不过我 AC 完以后,还是觉得还是不太严谨,还是乖乖用精确的方法判了一次
      
      2. 不可以定义 left 和 right 作为变量名
      虽然它们看上去似乎不是关键字,但是...别忘了在 ios 的输入和输出的格式控制里,是有 std::left 和 std::right 的,这里引一个网址 ( http://www.cplusplus.com/reference/ios/left/ )
      
      所以在导入命名空间 std 的同时,left 和 right 被一并导入,意味着我们不能再定义这两个变量,否则必将引起二义性
      
      < 这个坑以前倒是踩过,所以报错后立刻就发现了,哪里不对劲,但是,既然会再犯,说明它还是值得我重新整理一次的,因为再踩一次坑,无论我爬起来的有多快,其实还是说明,我对这个细节的掌握,其实还是没有到很熟悉的地步嘛~还是没到位啊! ╯﹏╰ >
      
      3. C++的四舍五入 setprecision
      博客: http://blog.csdn.net/mingzhentanwo/article/details/41082449
      
      其中有句话特别重要,一定要无比牢记:
      与setw()不同,setprecision(n)一直作用到下一个setprecisin(n)之前,所以,只需要写一个setprecision(n)即可。但setw()要每次都写
      
      4. 这题到最后时,还因为少写了一个 endl 换行符,卡了许久的 WA,最后还是用 uva 自带的 udebug 里的测试数据,才发现我的 WA 是错在哪... T^T
      唉...一定要注意细节,注意细节,这点再怎么强调也不为过...想想如果真的在正式场合,因为这个原因被卡 WA,出题方又没提供多的数据给我们检查的话,怕是一直发现不了这个bug,只能重敲一次了...揪心
    */


    /*
      查阅过的其他链接的整理:
      1. 浮点数精度问题,以及浮点数的“不可用符号比较的问题”:
      https://www.zhihu.com/question/36176935/answer/66516958
      http://www.cnblogs.com/crazyacking/p/4668471.html
      http://blog.csdn.net/cbnotes/article/details/38920511
      http://bbs.csdn.net/topics/90390941
      http://blog.sina.com.cn/s/blog_48d4cf2d0100qzfc.html
      https://www.zhihu.com/question/29064056?sort=created
      
      2. C++ 精度控制
      http://blog.csdn.net/mingzhentanwo/article/details/41082449
    */

    #include <iostream>
    #include <cstring>
    #include <iomanip>
    #include <cmath>
    #include <cstdio>
    #define rep(i, n) for ( int i = 0; i < (n); i++ )
    using namespace std;
    
    const int N = 1e3 +5;
    const double W = 1000.0;
    const double EPS = 1e-8;
    
    int n, vis[N];
    double x[N], y[N], r[N], _left, _right;
    bool jud; // 标记变量,标记是否能从左边界某点进入,右边界某点出来 
    
    // 顾名思义,不大于,这是重写了浮点型的  <= ,因为浮点数由于精度问题,是不能用符号直接判定的 
    bool notMoreThan ( double a, double b )
    {
    	return ( a < b ) || ( fabs (a - b) < EPS);
    }
    
    // 几何中,相切和相交,就是不相离的情况,所以定义为 notApart 
    bool notApart (int c1, int c2 )
    {
    	double a = sqrt ( pow( x[c1] - x[c2], 2 ) + pow ( y[c1] - y[c2], 2 ) );
    	double b = r[c1] + r[c2];
    	return notMoreThan(a, b);
    }
    
    void renewCircle ( int u )
    {
    	//与左边界相交或相切时,可能会更新 _left
    	 
    	if ( notMoreThan ( x[u], r[u] ) ) 
    	_left = min ( _left, y[u] - sqrt( pow( r[u], 2 ) - pow( x[u], 2 ) ) );
    	
    	//与右边界相交或相切时,可能会更新 _right
    	if ( notMoreThan ( W - x[u], r[u] ) ) 
    	_right = min ( _right, y[u] - sqrt( pow( r[u], 2 ) - pow( W - x[u], 2) ) );
    }
    
    bool dfs (int u) // 看能否到达底部
    {
    	if ( vis[u] ) return false; // 如果已经被访问,但是居然现在又被访问,说明在上下方向上,不会有,覆盖了 u,且能完整连接上下边界的连通快了 (毕竟如果有,u 之前被某个其他的圆通过 bfs 访问时,当时应该就已经能够确认 jud 为 false了,就不会再有机会,再来访问 u 这个圆形攻击范围了) 
    	vis[u] = 1; // 先来标记访问了这个区域 
    	
    	if ( notMoreThan ( y[u], r[u] ) ) return true; //单凭这个圆,就已经能形成,从上边界到下边界的完整连通块的情况 
    	
    	rep ( v, n ) //与该圆相切或相交的圆形中,有圆能形成,从上边界到下边界的完整连通块的情况  
    	if ( notApart(u, v) && dfs(v) ) return true;
    	
    	renewCircle(u); // 返回 false 前,先更新 _left 和 _right 的值 
    	return false;
    } 
    
    void solve ()
    {
    	while ( cin >> n )
    	{
    		jud = true;
    		_left = _right = W;
    		memset( vis, 0, sizeof(vis) );
    		
    		rep(i, n) cin >> x[i] >> y[i] >> r[i];
    		rep(i, n)
    		if ( y[i] + r[i] >= W && dfs(i) )
    		{
    			jud = false;
    			break;
    		}
    		
    		if (jud) cout << "0.00 " << fixed << setprecision(2) << _left << " " << W << " " << _right << endl;
    		else cout << "IMPOSSIBLE" << endl;
    	}
    }
    
    int main()
    {
    	solve();
    	return 0;
    }


  • 相关阅读:
    递归调用简单的讲解
    有关杭电acm问题的分类
    【jquery】切换标题与内容/点击后动态切换当前状态
    将数组某键值抽出作为新数组
    table表格制作
    如何导入大sql文件到mysql数据库
    二维数组按照某一键值进行排序
    利用PHP输出某一目录所有文件
    php结合js动态获取空间时间
    ie6不支持minheight的解决方案
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789386.html
Copyright © 2011-2022 走看看