贪心法实验

实验目的、内容及要求:

实验目的:

1.掌握贪心法的基本思想

2.使用贪心法求解实际问题

实验内容:

设海岸线是一条无限长的直线,一边是陆地一边是海洋,海洋中有一些小岛,每个小岛可以看作一个点,要在海岸线上安装一些雷达,每个雷达只能覆盖半径为d的圆形区域。海洋中的某个小岛能够被雷达覆盖到,当且仅当它和某个雷达之间的距离小于或者等于d。将海岸线定义为x轴,海洋在x轴上部,陆地在x轴下部,给定海洋中各个小岛的坐标位置(x,y),和雷达覆盖半径d,求覆盖所有小岛至少需要安装多少个雷达?

输入包含多组测试数据。每组测试数据的第一行包含两个整数 n (1<=n<=1000) 和d,分别表示海中的小岛数量和每个雷达的信号覆盖半径。接下来的n行,每一行包含两个整数,表示每个小岛的坐标。每组测试数据之间以一个空行间隔。当n=d=0时表示输入结束。

对每组测试数据输出一行,包含每组测试数据的编号,以及对应的最少需要安装多少雷达。如果不管安装多少雷达,信号都无法覆盖所有的小岛,输出-1。

题目来源:POJ1328(http://poj.org/problem?id=1328)

要求:撰写实验代码,提交到POJ结果必须是Accept。

实验仪器设备(实验环境):

普通主流PC,英特尔I5处理器2.0GHz,8GDDR4内存,500G硬盘,19寸液晶显示器。

实验过程包括实现思路、实验步骤/实现代码、实验结果/运行图

思路:简单贪心。以每个小岛为圆心作以半径为d的圆,找出与X轴相交的区间,意思为在这个区间上的任意一点都可以作为圆心,包含这个小岛。 这时就需要把所有小岛的在X轴的区间找到。 有交集的部分说明可以用一个圆覆盖。这是算出最小的圆,先排序,排序之后找到最左边小岛的右区间,然后看每一个小岛的左区间是否比右区间小,如果小的话,说明有交集,就可以用一个圆来覆盖。这样就将问题转换成了最大不相交区间集问题

对所有的活动,按区间右端点递增排序。引入变量j表示最近一次选中的活动的序号。先选取排序后的区间0,即选择一个具有最早结束时间的活动,令j的初值为0。

按照右端点递增的顺序遍历后面的区间,当遍历到区间i只要它的左端点大于前一个选取区间的右端点,说明这个两个区间不相交(也就意味着区间i和所有已经选中的区间都没有交集),则选该区间i,同时更新j的值为i。

遍历结束后,在此过程中选中的区间,就构成了需要求的最大不相交区间集。

具体代码如下:

#include

#include

#include

using namespace std;

const int Maxn = 1000 + 5;

struct node{

double l, r;//线段左右端点

bool operator < (const node &t) const {

        return r

    }

};

node arr[Maxn];

int main() {

int n, d, t = 1;

while(cin >> n >> d, n + d) {

int x, y;

bool bl = false;

for(int i = 0; i < n; i++) {

cin >> x >> y;//把坐标转换成线段的左右端点

if(y > d)bl = true;

arr[i].l = x * 1.0 - sqrt((double)d * d - y * y);//勾股定理

arr[i].r = x * 1.0 + sqrt((double)d * d - y * y);

}

if(bl) {//如果有岛屿的纵坐标大于雷达半径则直接输出-1并进入下次循环

cout << "Case " << t++ << ": " << -1 << endl;

continue;

}

sort(arr, arr + n);//排序

int sum = 1;//初始化为1,然后直接从第二个线段开始遍历

double maxr = arr[0].r;//当前雷达所在位置

for(int i = 1; i < n; i++) {

if(maxr >= arr[i].l)//有交集

maxr = min(maxr, arr[i].r);//更新maxr,选小的防止之前的线段被略过

else {//没有交集

maxr = arr[i].r;//更新maxr

sum++;

}

}

cout << "Case " << t++ << ": " << sum << endl;

}

return 0;

}

你可能感兴趣的:(算法)