POJ1328 -- 贪心算法和快速排序

<pre class="cpp" name="code"> 
 

一 。贪心策略:将雷达放置在合适的地方,使得包含的岛屿数量最多。

二。贪心策略具体分析

我们采用从左到右放置雷达。假设左边第一个岛屿是A(Xa,Ya),从左到右的岛屿依次是A B C ....

我们可以计算出岛屿A的雷达区间 : [Xa_left,Xa_right] , 使得在这个区间的雷达都可以覆盖到岛屿A。

Xa_left = Xa - sqrt (d^2 - Ya^2) ; Xa_right = Xa + sqrt(d^2 - Ya^2);

(其中d是雷达的辐射范围)

此时,可以将情况分为三种:如下图所示

 

三。快速排序

1.在这里定义了数据类型island,是指在这个区间[ x_left , x_right ]放置的雷达,都可以辐射到岛屿A 。同时,定义了一千个岛屿的数组arr[1000],里面分别存放了每个岛屿的雷达区间。

typedef struct island{  //定义一个岛屿所需雷达的区间
    double x_left;
    double x_right;
}island;
island arr[1000];

2.因为我们是从左往右放置雷达,所以排序的时候,是按x_left从小到大排序。

在这里,需要注意的是,交换数组里的x_left的同时,也要交换x_right。否则数组里存放的x_left和x_right将不对应。

int partition1(island* a ,int low, int high){ //快速排序,以x_left从小到大排序
    double temp = a[low].x_left;
    double temp_left;
    double temp_right;
    while(low<high){
        while(low<high && temp <= (a[high].x_left)){
            high--;
        }
        temp_left = a[high].x_left;  //交换的是arr[high]和arr[low]
        a[high].x_left = a[low].x_left;
        a[low].x_left = temp_left;
        temp_right = a[high].x_right;
        a[high].x_right = a[low].x_right;
        a[low].x_right = temp_right;

        while(low<high && temp >= (a[low].x_left)){
            low ++;
        }
        temp_left = a[high].x_left;  //交换的是arr[high]和arr[low]
        a[high].x_left = a[low].x_left;
        a[low].x_left = temp_left;
        temp_right = a[high].x_right;
        a[high].x_right = a[low].x_right;
        a[low].x_right = temp_right;
    }
    return low;

}

void fastsort(island* a ,int low, int high){  //快速排序,以x_left从小到大排序
    int pivot;
    if(low<high){
        pivot = partition1(a,low,high);
        fastsort(a,low,pivot-1);
        fastsort(a,pivot+1,high);
    }
}


四。贪心策略的实现

用cur表示,当前雷达可放置的最右端。

void Greedy(island* a , int n){
    double cur =a[0].x_right;  //当前最右端的雷达
    int i =0;
    for(i=1;i<n;i++){
        if(cur < a[i].x_left){  //需要一个新的雷达
            number++;
            cur = a[i].x_right;
        }else if(cur > a[i].x_right){// 此时岛屿0的雷达坐标包含岛屿1的雷达坐标, 所以当前雷达坐标选用雷达1的
            cur = a[i].x_right;
        }
    }
}


五。查看完整代码:

其中需要注意的是,输入的辐射范围d<=0时和y轴坐标>d时的处理,即无法完成雷达探测。输出-1.

#include <stdio.h>
#include <stdlib.h>
#include<math.h>

#define MAX 65535
typedef struct island{  //定义一个岛屿所需雷达的区间
    double x_left;
    double x_right;
}island;
island arr[1000];
int number=1;  //需要的雷达数量


int partition1(island* a ,int low, int high){ //快速排序,以x_left从小到大排序
    double temp = a[low].x_left;
    double temp_left;
    double temp_right;
    while(low<high){
        while(low<high && temp <= (a[high].x_left)){
            high--;
        }
        temp_left = a[high].x_left;  //交换的是arr[high]和arr[low]
        a[high].x_left = a[low].x_left;
        a[low].x_left = temp_left;
        temp_right = a[high].x_right;
        a[high].x_right = a[low].x_right;
        a[low].x_right = temp_right;

        while(low<high && temp >= (a[low].x_left)){
            low ++;
        }
        temp_left = a[high].x_left;  //交换的是arr[high]和arr[low]
        a[high].x_left = a[low].x_left;
        a[low].x_left = temp_left;
        temp_right = a[high].x_right;
        a[high].x_right = a[low].x_right;
        a[low].x_right = temp_right;
    }
    return low;

}

void fastsort(island* a ,int low, int high){  //快速排序,以x_left从小到大排序
    int pivot;
    if(low<high){
        pivot = partition1(a,low,high);
        fastsort(a,low,pivot-1);
        fastsort(a,pivot+1,high);
    }
}

void Greedy(island* a , int n){
    double cur =a[0].x_right;  //当前可探测的最右端
    int i =0;
    for(i=1;i<n;i++){
        if(cur < a[i].x_left){  //需要一个新的雷达
            number++;
            cur = a[i].x_right;
        }else if(cur > a[i].x_right){// 此时岛屿0的雷达坐标包含岛屿1的雷达坐标, 所以当前雷达坐标选用雷达1的
            cur = a[i].x_right;
        }
    }
}
int main()
{
    int n=0;
    int d=0;
    int caseNum = 0;

    //freopen("input.txt","r",stdin);
    while(scanf("%d%d",&n,&d)){
        if(n==0 && d==0){
            break;
        }

        memset(arr,MAX,sizeof(arr)); //数组初始化为最大值
        number = 1;
       caseNum++;
       int i=0;
       int flag = 0;
       int x ,y;
       for(i=0;i<n;i++){
            scanf("%d%d",&x,&y);   //读取每一个岛屿的坐标
            if(flag ==1 || y>d || d<=0){ //y>d和d<=0, 说明雷达无法覆盖到岛屿,标志位置1
                flag = 1;            //
                continue;           //continue语句,需要继续读接下来的数据
            }
            double temp = sqrt((double)(d*d-y*y));
            arr[i].x_left = x -temp;
            arr[i].x_right = x + temp;
       }


       if(flag == 1){
            printf("Case %d: -1\n",caseNum); //如果不能查找,那么则不进行排序和贪心
       }else{
            fastsort(arr,0,n-1);
            Greedy(arr,n);
            printf("Case %d: %d\n",caseNum,number);  //天坑!!!!"case 1:"后面还有个空格
       }

    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值