1. 程式人生 > >【演算法設計與分析】貪心策略——最佳郵局設定問題

【演算法設計與分析】貪心策略——最佳郵局設定問題

//總是感覺生活很空虛,就只能寫寫部落格看看書上上課這樣子。想出去,去一個遙遠的地方。

先來看一下題目:

有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; 
}