zoukankan      html  css  js  c++  java
  • 稻草人的祝福(构建贪心模型)

    题意:每个庄稼都可以看做是坐标系里面的一个点,当它处于某个稻草人的范围内时就可以视为被保护.每个稻草人的辐射范围都是一个半径为R的圆.稻草人只在坐标系的x轴上,而任何庄稼(x,y)都满足y>0。设计一个方案,用尽可能少的稻草人来保证所有庄稼都是安全的.若存在无法覆盖的庄稼或者给的稻草人不够覆盖所有庄稼,输出-1.

    分析:本题是很经典的一道构建贪心模型的题.

    我们以庄稼为圆心,仍以R为半径作圆,该圆与x轴有两个交点(前提是该庄稼的纵坐标小于圆的半径),则能够保护它的稻草人一定处于这两个点之间.是不是觉得这个转化很神奇!所以原题就转化成了给定n个区间,然后要给一些点染色,使得每个区间中都至少有一个点被染色,使染色数最少.

    区间染色问题,就是贪心的模板题了.以左端点排序或者以右端点排序都可以.我的代码中是以左端点排序,简述一下以左端点排序的思路:我们枚举这n个区间,记录右边界,如果当前枚举的区间的右端点比右边界小,右边界取较小值更新为该区间的右端点(这里就是贪心策略,画几个区间就明白了);如果当前枚举的区间的左端点比右边界大,ans++,右边界记得更新为当前区间的右端点.

    int n,R,c;
    int x[50005],y[50005];
    struct farm{
        double l,r;
    }a[50005];//结构体记录区间的左右端点,便于排序.
    void get_lr(int id,int x,int y){
        double xx=sqrt(R*R-y*y);
        a[id].l=x*1.0-xx;
        a[id].r=x*1.0+xx;
    }//将庄稼的坐标转化为区间的左右端点.
    bool cmp(farm a,farm b){
        if(a.l==b.l)return a.r<b.r;
        return a.l<b.l;
    }//按照左端点从大到小排序.
    int main(){
        while(1){//多组数据
    		n=read();R=read();c=read();
    //n个庄稼,R是稻草人能保护的圆的半径,c的稻草人的数量
    		if(!n&&!R&&!c)return 0;
    		int bj=0;
    		for(int i=1;i<=n;i++){
    	    	x[i]=read();y[i]=read();
    	    	get_lr(i,x[i],y[i]);
    	    	if(y[i]>R)bj=1;
    		}
    //如果有一个庄稼的纵坐标大于半径,肯定保护不了
    		if(bj){puts("-1");continue;}
    		sort(a+1,a+n+1,cmp);
    		int now=1,ans=1;
    		for(int i=2;i<=n;i++){
    	    	if(a[i].l>a[now].r){
    				ans++;now=i;
    	    	}
    	    	if(a[i].r<a[now].r)now=i;
    		}
    		if(ans<=c)printf("%d
    ",ans);
    		else puts("-1");
        }
        return 0;
    }
    
    
  • 相关阅读:
    【Vijos1159】岳麓山上打水 [迭代加深]
    【POJ3134】 Power Calculus [迭代加深]
    【2019.1.24】 搜索,动规 经典题目体验赛
    【noip2017】
    【poj3311】Hie With The Pie [状压dp]
    [bzoj3938] [Uoj #88] Robot
    [洛谷P4707] 重返现世
    [洛谷P4097] [HEOI2013] Segment
    KD-tree 学习小记
    NOI2019 酱油记
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10338524.html
Copyright © 2011-2022 走看看