1. 程式人生 > >演算法筆記之演算法初步(貪心)

演算法筆記之演算法初步(貪心)

     貪心演算法是以區域性最優解,而達到整體的最優解。貪心演算法的證明往往要比貪心解法本身要更難,所以在無法舉出反例的情況下要勇於使用。

                                                     1.簡單貪心

月餅

思路:將月餅按單價的高低排序,從單價高的月餅向單價低的遍歷,優先選擇單價高的月餅,其中每一步都是選擇當前最優的選擇來達到最後的結果。

注意要點:

  • 遍歷每一個,要區分需求量與庫存量的大小,區別對待
  • 最後結果要用double輸出,月餅庫存量和總售價也要用double來表示,不然容易出問題。
#include<iostream>
#include<algorithm>
using namespace std;

const double ep = 1e-8;
const int N = 1010;
struct moonCake{
	double quntity; //總量 
	double sell;// 總價錢 
	double price;// 單價 
}moonCakes[N];// 注意這裡為什麼要用double, price為double 

bool cmp(moonCake c1, moonCake c2){//排序函式 
	return c1.price > c2.price;
}

int main(){
	int n;
	double need;
	scanf("%d%lf", &n, &need);
	for(int i = 0; i < n; ++i){
		scanf("%lf", &moonCakes[i].quntity);
	}
	for(int i = 0; i < n; ++i){
		scanf("%lf", &moonCakes[i].sell);
		moonCakes[i].price = (1.0) * moonCakes[i].sell / moonCakes[i].quntity;
	}
	sort(moonCakes, moonCakes + n, cmp);// 從大到小排序 
	
	double money = 0.0, price = 0.0;//money為最後的結果  
	for(int i = 0; i < n; ++i){
		if(need){
			//當需求大於庫存量時 
			if( need >= moonCakes[i].quntity){
				money += moonCakes[i].sell;
				need -= moonCakes[i].quntity;
			}
			//當需求小於庫存量時 
			else{
				money += moonCakes[i].price * need;
				need = 0;
			}
		}
		else break;//當需求為0 
	}
	printf("%.2f", money);
	return 0;
}

	
	

注意:第一個數一定要非零

#include<iostream>
#include<stdio.h>
using namespace std;
int number[10] = {0};
int count = 0;

int main(){
	for(int i = 0; i < 10; ++i){
		scanf("%d", &number[i]);
		count += number[i];
	}
	
	int k = 1;
	while(number[k] == 0){// 為第一位,輸出非零數
		k++;
	}
	printf("%d", k);
	number[k]--;
	count--;
	
	k = 0;
	while(count){// 依次輸出每個數 
		while(number[k] == 0){
			k++;
		}
		printf("%d", k);
		number[k]--;
		count--;
	}
	return 0;
}

                                                          2.區間貪心

        給出N個開區間(x, y) ,從中選擇儘可能多的空間,使這些空間兩兩沒有交集。例如(1,3),(2,4),(3,5),(6,7),可以看到最多選擇三個,(1,3),(3,5),(6,7)。大體的思路是如果一個區間被另一個區間所包圍,那麼就選擇那個小的區間,能留出更多的空間給其他的區間。推廣開來,可以固定從尾端開始,將其按照X從小到大的值來排序,每次在選擇範圍內選X值大的區間(從後往前開始選擇,X值大的代表其區間為相對小的區間,如果是從前往後開始選擇,Y的值正好相反)

#include<iostream>
#include<algorithm>
using namespace std;

const int MAXL = 110;
struct interval{
	int x;
	int y;
}intervals[MAXL];

bool cmp(interval v1, interval v2){// 按照X的值從小到大排序 
	if(v2.x != v1.x) return v1.x < v2.x;
	else return v1.y > v2.y;// 如果X值相等,則Y大的排在前面 
}

int main(){
	int N;
	scanf("%d", &N);
	for(int i = 0; i < N; ++i){
		scanf("%d%d", &intervals[i].x, &intervals[i].y);
	}
	sort(intervals, intervals + N, cmp);// 排序 
	
	int x, y, count = 0;
	if(N){// 如果N存在,從後往前選擇最後一個區間 
		count = 1;
		x = intervals[N - 1].x;
	}
	for(int i = N - 2; i >= 0; --i){
		y = intervals[i].y;
		if( y <= x){// 開區間不能重合 
			x = intervals[i].x;
			count++;
		}
	}
	printf("%d", count);
	return 0;
}