主題
- 搜尋、排序、貪心
題目
參考作法
A - Flip Sort
- 題目說明:
- 給一堆數字,輸出要交換(只能相鄰交換)多少次,才能由小到大排好。
- 解題思路:
- Bubble sort
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <bits/stdc++.h> using namespace std; int main() { int n, a[1005]; while(cin >> n) { int ans = 0; for(int i = 0; i < n; ++i) cin >> a[i]; for(int i = 0; i < n; ++i) { for(int j = n - 1; j > i; --j) { if(a[j] < a[j - 1]) { swap(a[j], a[j - 1]); ++ans; } } } cout << "Minimum exchange operations : " << ans << '\n'; } return 0; }
B - Age Sort
- 題目說明:
- 給一堆數字,由小到大排序。
- 解題思路:
- std::sort()
- 小心 Presentation error
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; bool flag; while (cin >> n && n) { int a[n]; for(int i = 0; i < n; ++i) cin >> a[i]; sort(a, a + n); flag = false; for(auto i : a) { if(flag) cout << ' '; cout << i; flag = true; } cout << endl; } return 0; }
C - Conformity
- 題目說明:
- 輸出最多人選擇課的程組合的人數,若是最多的有多個,將人數相加。
- 解題思路:
- 將每行的課程排序後,再丟入 map 中統計。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; while(cin >> n && n) { int maxNum = 0, total = 0; map<string, int> msi; vector<string> vs; string input, line; while(n--) { line.clear(); vs.clear(); for(int i = 0; i < 5; ++i) { cin >> input; vs.push_back(input); } sort(vs.begin(), vs.end()); for(int i = 0; i < 5; ++i) line += vs[i]; ++msi[line]; } for(auto it = msi.begin(); it != msi.end(); ++it) if(it->second > maxNum) maxNum = it -> second; for(auto it = msi.begin(); it != msi.end(); ++it) if(it->second == maxNum) total += maxNum; cout << total << endl; } return 0; }
D - Guessing Game
- 題目說明:
- 依照題目模擬,看有沒有說謊。
- 解題思路:
- 模擬操作,最後看 right on 的值有沒有在區間中。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include <bits/stdc++.h> using namespace std; int main() { int n; while(scanf("%d ", &n) != EOF && n != 0) { int s = 1, e = 10; string str; while(getline(cin, str) && str != "right on") { if(str == "too high") e = min(e, n - 1); else if(str == "too low") s = max(s, n + 1); scanf("%d ", &n); } if(n >= s && n <= e) cout << "Stan may be honest\n"; else cout << "Stan is dishonest\n"; } return 0; }
E - Ancient Cipher
- 題目說明:
- 判斷第一行字串能不能依照題目的轉換方式變成第二行字串。
- 解題思路:
- 先紀錄彼此字母出現的次數並排序,再比對排序後數值是否相同即可。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include <bits/stdc++.h> using namespace std; int main() { string s1, s2; while(cin >> s1 >> s2) { int a[26] = {0}, b[26] = {0}; for(auto i : s1) ++a[i - 'A']; for(auto i : s2) ++b[i - 'A']; sort(a, a + 26); sort(b, b + 26); bool flag = true; for(int i = 0; i < 26; ++i) { if(a[i] != b[i]) { cout << "NO\n"; flag = false; break; } } if(flag) cout << "YES\n"; } return 0; }
F - Bridge Hands
- 題目說明:
- 依照給定方位的下一個人開始給牌,最後輸出要依照順序排列。
- 解題思路:
- 就模擬發牌並排序吧。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#include <bits/stdc++.h> using namespace std; using pcc = pair<char, char>; char c; vector<pcc> v[4]; bool cmp(pcc a, pcc b) { int ta[2], tb[2]; char cc[4] = {'C', 'D', 'S', 'H'}; char ct[13] = {'2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'}; for(int i = 0; i < 4; ++i) { if(a.first == cc[i]) ta[0] = i; if(b.first == cc[i]) tb[0] = i; } for(int i = 0; i < 13; ++i) { if(a.second == ct[i]) ta[1] = i; if(b.second == ct[i]) tb[1] = i; } if(ta[0] < tb[0]) return true; else if(ta[0] > tb[0]) return false; else { if(ta[1] < tb[1]) return true; else return false; } } void sortCard() { for(int i = 0; i < 4; ++i) { sort(v[i].begin(), v[i].end(), cmp); } } void printCard() { char oc[4] = {'S', 'W', 'N', 'E'}; char cc[4] = {'N', 'E', 'S', 'W'}; int ic[4][4] = {{1, 2, 3, 0}, {0, 1, 2, 3}, {3, 0, 1, 2}, {2, 3, 0, 1}}; int t; for(int i = 0; i < 4; ++i) { if(cc[i] == c) { t = i; break; } } for(int i = 0; i < 4; ++i) { cout << oc[i] << ":"; for(auto it : v[ic[t][i]]) cout << " " << it.first << it.second; cout << endl; } } int main() { while(cin >> c && c != '#') { string s; int temp = 0; for(int i = 0; i < 4; ++i) v[i].clear(); for(int i = 0; i < 2; ++i) { cin >> s; int len = s.size(); for(int j = 0; j < len; j += 2) { v[temp % 4].push_back({s[j], s[j + 1]}); ++temp; } } sortCard(); printCard(); } return 0; }
G - Vito’s Family
- 題目說明:
- 選出一個數,並計算彼此距離和最小的值。
- 解題思路:
- 中位數算距離和。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while(T--) { int n; cin >> n; int a[n]; for(int i = 0; i < n; ++i) cin >> a[i]; sort(a, a + n); int mid = a[n / 2], ans = 0; for(int i = 0; i < n; ++i) ans += abs(a[i] - mid); cout << ans << endl; } return 0; }
H - Shoemaker’s Problem
- 題目說明:
- 找出能使罰金最少的工作順序。
- 解題思路:
- 貪心法
- 依照 (罰金 / 時間) 的值,大到小排序。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <bits/stdc++.h> using namespace std; using pdi = pair<double, int>; bool cmp(pdi a, pdi b) { return a.first > b.first; } int main() { int T; cin >> T; while(T--) { int n; cin >> n; vector<pdi> v; for(int i = 1; i <= n; ++i) { int a, b; cin >> a >> b; v.push_back({(b * 1.0 / a), i}); } sort(v.begin(), v.end(), cmp); bool flag = false; for(auto it : v) { if(flag) cout << ' '; cout << it.second; flag = true; } cout << endl; if(T) cout << endl; } return 0; }
I - The Bus Driver Problem
- 題目說明:
- 公車工作安排,輸出雇主最少需要支付的加班費。
- 解題思路:
- 先依照早晚排序,頭尾配對(最大配最小),最後計算加班費的金額。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <bits/stdc++.h> using namespace std; int main() { int n, d, r; while(cin >> n >> d >> r && n && d && r) { int morning[n], night[n]; for(int i = 0; i < n; ++i) cin >> morning[i]; for(int i = 0; i < n; ++i) cin >> night[i]; sort(morning, morning + n); sort(night, night + n); int ans = 0; for(int i = 0; i < n; ++i) { if(morning[i] + night[n - i - 1] > d) ans += ((morning[i] + night[n - i - 1] - d) * r); } cout << ans << endl; } return 0; }
J - Watering Grass
- 題目說明:
- 計算最少需要多少個噴水頭才能覆蓋整個區域,若都不行輸出 -1。
- 解題思路:
- 先轉換成一維。
- 貪心法
- 區間覆蓋
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#include <bits/stdc++.h> using namespace std; using pdd = pair<double, double>; bool cmp(pdd a, pdd b) { if(a.first == b.first) return a.second > b.second; else return a.first < b.first; } int main() { int n; double l, w; while(cin >> n >> l >> w) { w /= 2; double p, r; vector<pdd> v; for(int i = 0; i < n; ++i) { cin >> p >> r; if(r > w) { double dd = sqrt(r * r - w * w); v.push_back({p - dd, p + dd}); } } sort(v.begin(), v.end(), cmp); int ans = 0; double right = 0.0; for(int i = 0; i < v.size(); ++i) { if(v[i].first > right) break; for(int j = i + 1; j < v.size() && v[j].first <= right; ++j) { if(v[j].second > v[i].second) i = j; } ++ans; right = v[i].second; if(right >= l) break; } if(right >= l) cout << ans << endl; else cout << "-1\n"; } return 0; }
K - Ultra-QuickSort
- 題目說明:
- 輸出最少要交換的數量。
- 解題思路:
- 用 merge sort 求逆序數對。
- 大佬們要用 BIT 去解也行。
- 程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#include <bits/stdc++.h> using namespace std; long long ans = 0; long long a[500005]; void mergeSort(long long *arr, int len) { if(len <= 1) return; int leftLen = len / 2, rightLen = len - leftLen; long long *leftArr = arr, *rightArr = arr + leftLen; mergeSort(leftArr, leftLen); mergeSort(rightArr, rightLen); static long long tmp[500005]; long long tmpLen = 0, l = 0, r = 0; while(l < leftLen && r < rightLen) { if(leftArr[l] < rightArr[r]) tmp[tmpLen++] = leftArr[l++]; else { tmp[tmpLen++] = rightArr[r++]; ans += leftLen - l; } } while(l < leftLen) tmp[tmpLen++] = leftArr[l++]; while(r < rightLen) tmp[tmpLen++] = rightArr[r++]; for(int i = 0; i < tmpLen; ++i) arr[i] = tmp[i]; } int main() { int n; while(cin >> n && n) { ans = 0; for(int i = 0; i < n; ++i) cin >> a[i]; mergeSort(a, n); cout << ans << endl; } return 0; }