编程语言
首页 > 编程语言> > 贪心算法_POJ1328和POJ2586小结

贪心算法_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