【算法设计与分析】贪心策略——最佳邮局设置问题

//总是感觉生活很空虚,就只能写写博客看看书上上课这样子。想出去,去一个遥远的地方。

先来看一下题目:

有n户人家坐落在从西向东的一条街上。从街西头向东数,第i户的房子与街西头的距离是H[i]米,(1≤i≤n), H[1]< H[2] < H[3] … < H[n] ,假设街上没有邮局。现在,要在街上建一些邮局使得任一户人家到最近一个邮局的距离不超过1000米。请设计一个O(n)时间的算法以确定最少需要见的邮局收,并给出每个邮局到街西头的距离。

看到这道算法题,我有点羡慕这条街的人,寄信肯定超级方便,但也不禁有疑问,这个年代还要不要设置这么多邮局,因为不知道是不是还有很多人在写信,但是我特想写封信寄给她。蓦然想起来那首《从前慢》,"从前的日色变得慢/车,马,邮件都慢/一生只够爱一个人"。

正所谓一步一个脚印,既然要建邮局,还是那么多邮局,我们必然要从第一个邮局建起,邮局我们就假设为一个P数组,int型,里面存储邮局距离街最西头王大姐家菜地的距离。那么,第一个邮局便是P[1],回顾一下题目,我们需要确定最少的邮局数量,也就是说我们要让邮局的存在效用最大化,即每个邮局的覆盖范围最广,那么对P[1]来讲,必然是P[1]设立在H[1]+1000处时最为合适,附图来说:



从图里面可以看出,P[1]设立在H[1]+1000处时覆盖范围最广,在此点的右边设立,不符合题意,第一户人家距离邮局太远,若在左边,那么范围不够大,会多出第一户人家到菜地的一些距离,这个距离对邮局设立来说意义不大。将第一个邮局设立之后,应当考虑P[2],P[3]...假若H[2]等一些户人家在段1或者段2之中,那么我们便无需再对这些人家考虑单独设立邮局,直到距离P[1]+1000点最近且在此点东边的下一户人家重新开始考虑设立P[2],方法与H[1]和P[1]相同,以此类推到P[n]。

这里要注意的是,按照算法,最后一户人家如果距离其左边的邮局距离大于千米,那么在其右边千米处会设立一个邮局,也就是在街的最东头设立了一个邮局,这就有点尴尬了,专门为最后一户人家设立的还距离那么远。因此我们将此邮局设立在最后一户人家附近即可。

下面给出代码:

#include<stdio.h>
#define MAX 101
int Post_office(int P[],int H[],int n){
    P[1]=H[1]+1000;  //第一个邮局位置
	int m=1;
	int i;
	for(i=2;i<=n;i++){
        if(H[i]>P[m]+1000){
            m++;
			P[m]=H[i]+1000;
		}
	}
	if(P[m]>H[n])
	    P[m]=H[n];  //最后一个邮局不需要在最后一户人家之外

	return m;
}
int main(){
    int P[MAX];
	int H[MAX];
	int n=0;
	int m=0;
	printf("Please input the quantity:\n");
	scanf("%d",&n);
	printf("Please input the family`s distance:\n");
	for(int i=1;i<=n;i++){
        scanf("%d",&H[i]);
	}
	m=Post_office(P,H,n);
    printf("There are %d post office,there are:\n",m);
	for(int i=1;i<=m;i++){
	    printf("%d ",P[i]);
	}
	return 0; 
}

 

  • 17
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值