洛谷-紀念品分組(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;
}