zoukankan      html  css  js  c++  java
  • POJ-1328-放置雷达

    这是一道贪心的题目,首先我们要知道,我们放置雷达的话我们可以做一个转换,就是已知岛屿的点坐标的时候,我们可以算一下,这个点以d为半径与x轴交点之间的线段在x轴上的投影,然后我们只需要在这个投影范围内设置一个雷达就可以了。

    然后我们读入数据的时候,因为题目中说道,如果计算不出结果我们就输出-1,一般来是可以得到结果的,所以如果出现异常,那肯定是数据的锅。

    我们读的时候判断一下y值,如果大于d的值的话,我们就给一个flag标记,然后在读入完成之后,直接输出-1,跳出这重循环,继续对下一组数据进行操作。

    根据之前的投影,我们只需要记录每个岛屿的投影开始的x值和结束的x值就可以了。

    接下来我们就开始计算这雷达的安放数目了,我们可以知道如果在同一个雷达的作用范围可以覆盖多个岛屿的话,我们就在这些处于同一范围的岛屿的最后一个岛的投影开始x值处,安放一个雷达就可以了。

    这是因为如果这些岛屿若不能被这个雷达覆盖的话,就是两种情况:

    第一种情况就是,其中的一个岛屿的它的左端点已经超过了最右边的那个端点的开始x值,这样就与我们的假设矛盾了,所以不成立。

    第二种情况就是,其中的一个岛屿的右端点小于了最右边的那个岛屿的左值,这样子的话,它又与我们的假设相矛盾了。因为如果小于左值,就说明它的范围已经不跟后面的岛是同一个范围的了,一个雷达是不可能覆盖这些岛屿的。

    我们执行的时候,也是进行两重循环,第一重循环推进岛屿,第二重循环就从上次未覆盖的岛屿开始直到一重循环的i值-1的位置,进行比对,比较这之间的岛屿的结束位置是否大于岛屿i的开始位置,如果大于,就不做任何操作。

    如果小于就说明除了岛屿i之外,上次未覆盖岛屿到i-1的岛屿是处在同一个雷达范围之下的,我们在i-1直接设置一个雷达即可。

    这样子的话,就是ans++的操作,然后更新最新的未被覆盖的岛屿的位置,然后跳出内层循环。

    但是ans这个值的话,我们要给它设置成1,因为如果只有一个岛屿的话,我们进入循环之后就会发现i=0,此时第一次进入,最新未被覆盖的岛屿位置也是0,然后我们无法进入内层循环,然后就无法进行++操作。

    但是我们设置为1的目的并不是为了第一个岛,这也与我们的初衷相悖,与我们的思路不一样,我们设置的目的是为了给最后一个岛进行加一的操作。

    我们可以分析一下, 最后一个岛的情况,第一,它被之前的岛覆盖了,外层循环走到最后一个岛,内层循环进行比较,然后发现没有结束的岛屿位置,也就是下一次的岛屿不能全部覆盖的那个岛屿位置。

    我们失去了结束的位置,然后ans就不能++,所以我们直接加1。另一种情况就是最后一个岛屿也不被覆盖,但是内层循环依旧找不到结束的位置,这样内层循环结束,外层循环结束,ans依旧没有加加。

    所以我们直接给它设置成1,至于贪心算法的正确性其实还有几句话,但是看不看都已经无所谓了,直接看代码去吧。

    正确性:

    假设你觉得有一个雷达的放置序列是最少的,最佳的,然后我们按照上面的方法得出的是另一个最佳结果。

    好,我们来比较这两个序列,设它们的开始是x1和y1(都是x的坐标)。

    如果x1<y1,此时,x1所覆盖的岛屿必能被y1所覆盖,这时候我们就可以用y1替换x1。

    如果x1>y1,这时候又分为两种情况,第一就是y1<x1<y2,因为x1不能覆盖y2范围内的岛屿,所以我们这时候放置的y1不会有损失,我们可以覆盖所有的岛屿。

    如果它大于x2,这时候,根据我们的贪心策略,如果我们在i放置雷达,是因为我们如果在i+1的位置放置雷达,那就无法覆盖i位置上的雷达了。

    所以如果x1>y2的话,它本身也无法覆盖1位置上的雷达,所以它本身就不是一个正确的策略了。

    所以贪心解法就是正确的。

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const double eps=1e-6;
    
    struct Island {
    	double Sx,Ex;
    	bool operator < (const Island &b)const {
    		return Ex<b.Ex;
    	}
    }island[1010];
    
    int main()
    {
    	int n,d,x,y,cnt=1;
    	while (~scanf("%d%d",&n,&d)&&n&&d) {
    		int error=0;
    		for (int i=0;i<n;i++) {
    			scanf("%d%d",&x,&y);
    			if (y>d)
    				error=1;
    			island[i].Sx=x-sqrt(d*d-y*y);
    			island[i].Ex=x+sqrt(d*d-y*y);
    		}
    		if (error) {
    			printf("Case %d: %d
    ",cnt++,-1);
    			continue;
    		}
    		sort(island,island+n);
    		int end=0;
    		int ans=1;
    		for (int i=0;i<n;i++) {
    			for (int j=end;j<i;j++) {
    				if (island[i].Sx-island[j].Ex<eps) {
    					continue;
    				}
    				else {
    					ans++;
    					end=i;
    					break;
    					//此时i-1已经被覆盖 
    				}
    			}
    		}
    		printf("Case %d: %d
    ",cnt++,ans);
    	}
    	return 0;
    }
  • 相关阅读:
    没有找到MSVCR100.dll解决方法
    Python用subprocess的Popen来调用系统命令
    我是怎样成长为系统架构师的
    【java读书笔记】——Collection集合之六大接口(Collection、Set、List、Map、Iterator和Comparable)
    SQLite的SQL语法
    MVC中使用AuthorizeAttribute做身份验证操作
    windows知识点
    java实现第五届蓝桥杯斐波那契
    java实现第五届蓝桥杯绳圈
    java实现第五届蓝桥杯绳圈
  • 原文地址:https://www.cnblogs.com/xyqxyq/p/10211336.html
Copyright © 2011-2022 走看看