贪心算法_POJ1328和POJ2586小结
作者:互联网
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;
}
标签:count,POJ1328,right,temp,int,POJ2586,line,left,贪心 来源: https://blog.csdn.net/Alanadle/article/details/116571146