POJ-3485-Highway

原题
Bob is a skilled engineer. He must design a highway that crosses a region with few villages. Since this region is quite unpopulated, he wants to minimize the number of exits from the highway. He models the highway as a line segment S (starting from zero), the villages as points on a plane, and the exits as points on S. Considering that the highway and the villages position are known, Bob must find the minimum number of exists such that each village location is at most at the distance D from at least one exit. He knows that all village locations are at most at the distance D from S.

Input
The program input is from a text file. Each data set in the file stands for a particular set of a highway and the positions of the villages. The data set starts with the length L (fits an integer) of the highway. Follows the distance D (fits an integer), the number N of villages, and for each village the location (x,y). The program prints the minimum number of exits.

White spaces can occur freely in the input. The input data are correct and terminate with an end of file.

Output
For each set of data the program prints the result to the standard output from the beginning of a line. An input/output sample is in the table below. There is a single data set. The highway length L is 100, the distance D is 50. There are 3 villages having the locations (2, 4), (50, 10), (70, 30). The result for the data set is the minimum number of exits: 1.

Sample Input
100
50
3
2 4
50 10
70 30
Sample Output
1
题意:
在直角坐标系上,有一条长为L的公路在x轴上从0到L。同时在直角坐标系上还有n个村庄每一个都有自己的坐标(x,y)。现在要在这条公路上设置出口,要求每一个村庄至少和一个出口之间的距离小于D,问最少需要建立几个出口。
题解:
一道贪心题目,我们可以通过勾股定理将其转化为直线上区间的问题,通过勾股定理计算出每一个村庄在x轴上的映射,映射为出口可以存在的区间。之后按照起始点从小到大排序即可。已知有n个村庄,那么最多设置出口为n个。记录一个起始点为start,循环遍历,若是该村庄的st小于start,则说明在这个区间内可以设置一个出口既可以满足上一个村庄又可以满足下一个村庄,那么可以减少一个出口的设置;若是st大于start,则说明在该区间内设置出口已经不能满足下一个村庄,更新start为下一个村庄的ed。(更多细节见代码)
附上AC代码:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int l,d,n;
struct point
{
    double x,y;//记录村庄的位置
    int st,ed;//转化后村庄在x轴上的区间
}a[100005];
void findse(int i)//寻找st和ed
{
    double dx=sqrt(d*d-a[i].y*a[i].y);//勾股定理
    a[i].st=ceil(a[i].x-dx);//向上取整
    a[i].ed=floor(a[i].x+dx);//向下取整
    if(a[i].st<0)a[i].st=0;//公路从0到L
    if(a[i].ed>l)a[i].ed=l;
}
bool cmp(point a,point b)
{
    if(a.st==b.st)
        return a.ed<b.ed;
    return a.st<a.st;//按st从小到大排序,当st相等时ed也从小到大
}
int main()
{
    while(cin>>l>>d>>n)
    {
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].x>>a[i].y;
            findse(i);//寻找在x轴上出口可以存在大的区间
        }
        int cnt=n;//最多设置出口为n个
        sort(a+1,a+n+1,cmp);//排序
        //for(int i=1;i<=n;i++)
        //{
            //cout<<a[i].st<<" "<<a[i].ed<<endl;
        //}
        int start=-1;//定义起始点为-1
        for(int i=1;i<=n;i++)
        {
            if(a[i].st>start)//如果下一个起始点不再上一个的区间内,更新start
            {
                start=a[i].ed;
                continue;//很重要,否则下面的if语句一直成立
            }
            if(a[i].st<=start)//如果起始点再上一个区间内则可以减少一个出口
            {
                cnt--;
            }
        }
        cout<<cnt<<endl;
    }
    return 0;
}

欢迎评论!

猜你喜欢

转载自blog.csdn.net/wjl_zyl_1314/article/details/83117620
今日推荐