POJ1386链接http://poj.org/problem?id=1386
题意就是说给定小岛坐标,给出雷达覆盖范围,求出雷达最小个数
我们发现除却岸边到雷达的y轴距离大于覆盖半径r之外,总是可以与海岸线有一个或者两个交点,我们可以使用一个结构体(含有连个double类型的变量来进行存储)
于是原题目就变成了关于线段的最小重叠问题了,我们的贪心策略也很简单 :
首先:
1>对结构体按照left大小进行排序
2>判断当前temp.right>line[i].right时,直接令temp=line[i],进行转移,如果temp.right<line[i].left时表明雷达够不着了,所以雷达数量++,再转移当前对象temp=line[i], 最后有的同学会问:为啥不考虑temp[right]>line[i].left&&tmep.right<line[i].right呢?问得好!!!(自问自答,鼓掌!!!),因为我们当前使用的雷达只要在lne[i].left到temp.right之间就好了,后面加入的线段因为line[i+1].left>line[i].left,所以肯定不会到前面去,直到跳转到第二种情况:temp.right<line[i].left.
献上代码:
#include<algorithm> #include<cstdio> #include<cmath> #include<cstdlib> /* 这道题目本质上是对于线段重叠问题,这是一种很经典的贪心算法的思想: 1.根据元素left排序,选择标志结构体,每一次比较只会有三种情况 1>temp.rihgt>p[i].left ,对于第一种情况其实不用进行操作,因为后面的left值一定是大于前面的left的值,只要最后没有超过temp.right的界限,最终都是可以使用一个雷达来锚定这个位置 2>temp.right>p[i].right 3>temp.right<p[i].left */ typedef struct Line{ double left; double right; }Line; /** bool cmp(Line a,Line b) { return a.left<b.left; //从小到大排序 } */ void sort_(Line* a,int land_count) { Line temp; for(int i=0;i<land_count;++i) { for(int j=i+1;j<land_count;++j) { if(a[i].left>a[j].left) { a[i]=temp; temp=a[j]; a[j]=temp; } } } } int main() { int count=0; int land_count; int r; while(true) { scanf("%d %d",&land_count,&r); if(land_count==0&&r==0) break; double *p=(double*)malloc(sizeof(double)*land_count*2); double *px=p; double *py=p+land_count; double temp; for(int i=0;i<land_count;++i) { scanf("%lf %lf",&px[i],&py[i]); } int radar=1; bool impossible=false; Line* line=(Line*)malloc(sizeof(Line)*land_count); for(int i=0;i<land_count;++i) { if(fabs(py[i])>r) { impossible=true; radar=-1; //radar=-1表示不存在这种情况 break; } temp=sqrt(r*r-py[i]*py[i]); line[i].left=px[i]-temp; line[i].right=px[i]+temp; } if(!impossible) { //1.先初始化雷达个数 radar=1; //2.再对雷达线段进行排序 sort_(line,land_count); Line _temp=line[0]; //3.进行贪心环节,寻找局部最优解 for(int j=1;j<land_count;++j) { if(_temp.right>line[j].right) { _temp=line[j]; }else if(_temp.right<line[j].left) { _temp=line[j]; radar++; } } } printf("Case %d: %d\n",++count,radar); free(p) ; free(line); } return 0; }
POJ2568链接http://poj.org/problem?id=1386
这道题枚举可以做,但是贪心更优(不知道是不是自己太贪心了),每次写对贪心的题总是感觉莫名的舒爽(而且还是关于钱的,哈啊哈哈啊哈哈),这道题的贪心思想很明显:我们只要将亏损的月份尽量放在当前区间的后面,这8个区间,1~5 , 2~6… 最后再统计一下钱数总和即可.比如1~5区间如果有亏损就放依次放在5,4,3,…
#include<iostream> using namespace std; int mon[12]; int add(int *mon,int start) { int sum=0; for(int i=start;i<start+5;++i) { sum+=mon[i]; } return sum; } int main() { int s,d; while(cin>>s>>d&&s>0&&d>0) { for(int i=0;i<12;++i) mon[i]=s; for(int i=0;i<8;++i) { for(int j=0;j<5;++j) { int flag=add(mon,i); if(flag>0) mon[i+5-j-1]=-d; else break; } } int all=0; for(int i=0;i<12;++i) { all+=mon[i]; } if(all<0) { cout<<"Deficit"<<endl; //Defilcit,啊啊啊啊,英语单词杀我,defilicit,-->sit } else cout<<all<<endl; } return 0; }