貪心練習題集

洛谷-紀念品分組(1094)

題目鏈接

問題分析:

根據問題描述,得出最優解應該滿足分組儘可能少。此外要求,每組至多兩件物品且價值儘量均勻,而且還不能超過規定價格。
找出問題所在,解便不難得出。倘若價值最大的和價值最小的都沒有超過規定價格,則次小和次大兩兩組合也能滿足要求。如若不能,則價值最大的便自己單獨一組,最小的和次大的組合再次比較,看是否滿足要求。

代碼示例:
#include<iostream>
#include<algorithm>
using namespace std;

int main(){
 	int w, n;
 	cin >> w >> n;
 	int value[n];
 	for(int i = 0; i < n; i++){
  	cin >> value[i];
 	}
 	sort(value, value+n);
 	int i =0, j = n-1, count = 0;
 	while(i <= j){
  		if(value[i] + value[j] <= w){//尋找價值較大的同價值較小的組合
   			j--;
   			i++;
  		} else {//價值較大的單獨放置
   			j--;
  		}
  		count++;
 	}
 	cout << count;
 	return 0;
}

上述代碼,對程序執行貢獻最大的是一次排序,需要O(nlogn)的時間,因此時間複雜度爲O(nlogn)。

洛谷-合併果子(1090)

求解過程

最大整數

題目鏈接

問題分析:

典型的貪心求解問題,問題的最優解要求得到的整數最大。因此每次局部求解過程中,都應該找到序列中的最大值。這裏的局部最大值,並非真正意義上的最大值,而是應該選擇每個數的第1、2、3……位上的數值儘可能大的數。例如123和72,在實際意義上,123>72,但是本題,72的首位是7,123首位是1,顯然7>1,因此應首選72,而不是123。

代碼示例:
#include<iostream>
#include<algorithm>
using namespace std;

bool cmp(string a, string b){
 	if(a + b > b + a) return 1;
 	else return 0;
}

int main(){
 	int n;
 	cin >> n;
 	string ars[n];
 	string res = "";
 	for(int i = 0; i < n; i++)
  	cin >> ars[i];
 	sort(ars, ars + n, cmp);
 	for(int i = 0; i < n; i++)
  		res += ars[i];
 		cout << res;
 	return 0;
}

美元匯率

題目鏈接

問題分析:

初看題目,想的太複雜,原因在於以下此種情況的考慮:

樣例:5
400 600 300 500 300 250

如上例,第一天購買,但相鄰的第二天卻不符合,是否需要繼續向後匹配?開始的想法是需要。但是分析發現,題目要求最大收益,什麼情況收益最大?==穩賺不賠的情況下進行儘量多次數的交換。==仍如上例情況,第二天買,第三天賣的收益肯定是大於第一天的,原因在於第二天能夠買到的馬克大於第一天(第二天與第三天的差值要更大-利潤空間更大)。

代碼示例:
#include<cstdio>
using namespace std;

int main(){
 	int n;
 	scanf("%d", &n);//天數
 	int m[n];
 	double t = 100.0;
 	for(int i = 0; i < n; i++){
  		scanf("%d", &m[i]);
 	} 
 	for(int i = 0; i < n-1; i++){
  		if(m[i] > m[i+1])
   			t *= (double)m[i]/m[i+1];
 	}
 	printf("%.2f", t);
 	return 0;
}
/*
5
400 300 500 300 250*/

零件分組:

題目鏈接

問題分析:

題目要求對零件長度和重量分組,且長度和重量皆呈不下降趨勢。
法一:可以先確保長度或重量二者之一呈不下降趨勢(排序實現)。另一屬性可以採用暴力遍歷求解:遍歷序列,直至沒有逆序對爲止。舉個例子,如下圖所示:
在這裏插入圖片描述
如圖所示,已按其中之一屬性排序,因此只需要求解對立屬性序列即可。遍歷第二行序列,若存在逆序對(8,4即爲逆序對)則分組記錄加1,暴力掃描直至不存在逆序對。我們可以設置一個布爾類型數組,若元素滿足條件(呈不下降趨勢)則可以設置數組爲false,表示此數組已加入一個分組。例如,3 < 5 < 8滿足條件,因此三個加入一組(布爾類型數組置false,表示已從待排序列中刪除),此組中的最大值已爲8,後續序列無滿足情況,所以需要重新安排一組。

代碼示例:
#include<iostream>
#include<algorithm>
using namespace std;

struct A{
 	int h, w;
};

bool cmp(A x, A y){
 	if(x.h == y.h) return x.w < y.w;
 	return x.h < y.h;
}

int main(){
 	int n, count = 0, b = 0, b2 = -1;
 	cin >> n;
 	bool visted[n];
 	bool flag = true;
 	A a[n];
 	for(int i = 0; i < n; i++){//init 
  		visted[i] = true;
  		cin >> a[i].h >> a[i].w;
 	}
 	sort(a, a+n, cmp);
 	while(b != b2){
  		b2 = b;
  		count++;
  		int t = a[b].w;
  		for(int i = b+1; i < n; i++){
   			if(a[i].w >= t && visted[i]){
   		 		t = a[i].w;
    				visted[i] = false;
   			} else if(a[i].w < t && flag){
    				b = i;
    				flag = false;
   			}
  	}
  		flag = true;
 	}
 	cout << count;
 	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章