簡報:水餃
講師:Roy
烤肉好吃
甚麼突然眼前一亮
這是4年前你們學長的學長的學長的學長遇到的困擾
這是前年你們學長的學長的學長的簡報
明年的學術,你知道該怎麼做了吧
每次run完整個陣列一定會把最大/最小值搬到最右邊
但不一定把最小/最大值搬到最左邊
| 3 | 5 | 2 | 1 | 6 |
| 3 | 2 | 5 | 1 | 6 |
| 3 | 2 | 1 | 5 | 6 |
| 2 | 3 | 1 | 5 | 6 |
| 2 | 1 | 3 | 5 | 6 |
| 1 | 2 | 3 | 5 | 6 |
for(int i = 0; i < n; i++) {
for(int j = 0; j < n - i; j++) {
if(arr[j] >= arr[j + 1]) {
swap(arr[j], arr[j + 1]);
}
}
}好麻煩
O(N²)
有沒有快一點的
std::sort
而且他是O(N log N)
自己刻出的函式名 自訂排序方式
vector <int> vec;
for (int i = 2; i <= 10; i += 2) vec.push_back(i);
for (int i = 1; i <= 10; i += 2) vec.push_back(i);
sort(vec.begin(), vec.end()); //預設升序
// {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sort(vec.begin(), vec.end(), greater <int>())
// {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}int arr[10] = {2, 4, 6, 8, 10, 1, 3, 5, 7, 9};
sort(arr, arr+10, greater <int>());O(N log N)
bool cmp(int a, int b) {
return a > b;
}vector <int> vec;
for (int i = 2; i <= 10; i += 2) vec.push_back(i);
for (int i = 1; i <= 10; i += 2) vec.push_back(i);
sort(vec.begin(), vec.end(), cmp);
// {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}{}
{}
{0, 1}
{}
{2}
{1}
{1, 2}
{0}
{0, 2}
{0, 1}
{0, 1, 2}
{0}
{1}
{}
{0}
#include<bits/stdc++.h>
using namespace std;
vector<int> subset;
int n = 3;
void search(int k) {
if (k == n) {
for (int i = 0; i < subset.size(); i++)
cout << subset[i] << " ";
cout << endl;
return;
} else {
// 不選擇第 k 個元素
search(k + 1);
// 選擇第 k 個元素
subset.push_back(k);
search(k + 1);
// 移除最後一個元素
subset.pop_back();
}
}
int main() {
search(0);
}用 0 或 1 來表示有沒有選
選的情況可以表示成一個二進制數字
| 數字 | 二進制數字 | 子集合 |
|---|---|---|
| 0 | 000 | ∅ |
| 1 | 001 | 0 |
| 2 | 010 | 1 |
| 3 | 011 | 0, 1 |
| 4 | 100 | 2 |
| 5 | 101 | 0, 2 |
| 6 | 110 | 1, 2 |
| 7 | 111 | 0, 1, 2 |
#include<bits/stdc++.h>
using namespace std;
int main() {
int n = 3;
for (int s = 0; s < (1 << n); s++) {
vector<int> subset;
for (int i = 0; i < n; i++)
if (s & (1 << i)) subset.push_back(i);
for (int i = 0; i < subset.size(); i++)
cout << subset[i] << " ";
cout << endl;
}
}剛剛那個是找子集合
顯然也可以要你找有幾種排列方式
0 1 2
0 2 1
1 0 2
1 2 0
2 0 1
2 1 0
{}
{0}
{2, 1}
{2, 0}
{0, 2}
{0, 1}
{2}
{1}
{1, 2}
{1,0}
{0, 1, 2}
{0, 2, 1}
{1, 0, 2}
{1, 2, 0}
{2, 0, 1}
{2, 1, 0}
#include<bits/stdc++.h>
using namespace std;
int n = 3;
vector<int> permutation;//排列結果
vector<bool> chosen(n);//是否選擇
void search() {
if (permutation.size() == n) {
for (int i = 0; i < n; i++)
cout << permutation[i] << " ";
cout << endl;
} else {
for (int i = 0; i < n; i++) {
if (chosen[i]) continue;
chosen[i] = true;
permutation.push_back(i);
search();
chosen[i] = false;
permutation.pop_back();
}
}
}
int main() {
search();
}#include<bits/stdc++.h>
using namespace std;
int main() {
int n = 3;
vector<int> permutation;
for (int i = 0; i < n; i++) {
permutation.push_back(i);
}
do {
for (int i = 0; i < n; i++)
cout << permutation[i] << " ";
cout << endl;
} while (next_permutation(permutation.begin(),permutation.end()));
}int coins[] = {10, 5, 1};
int n = 28, cnt = 0;
for (int i = 0; i < 3; i++) {
cnt += n / coins[i];
n %= coins[i];
}
cout << cnt;
但不見得類似的都能這樣寫
例如 {1, 3, 4} 湊 6 就會發現燒雞了
怎麼辦 dp 後面會講
先試試看
餐點吃完所需要的時間 e 比較長先吃
因為他邊吃的同時,老闆還能繼續煮別人的
越早開始吃,吃飯時間和別人的烹煮時間可以重疊進行
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
int n;
while (cin >> n) {
if (!n) break;
vector<pair<int, int>> v;
for (int i = 0; i < n; i++) {
int c, e;
cin >> c >> e;
v.push_back({e, c});
}
sort(v.begin(), v.end(), greater<pair<int, int>>()); // pair 的 greater 會先比較第一項大小再比較第二項
int curTime = 0, maxTime = 0;
for (int i = 0; i < n; i++) {
curTime += v[i].second;
maxTime = max(maxTime, curTime + v[i].first);
}
cout << maxTime << endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
int n;
cin >> n;
vector<long long> coins(n);
for (int i = 0; i < n; i++) cin >> coins[i];
sort(coins.begin(), coins.end());
int smallest = 1; //目前可湊 [1, smallest)
for (int i = 0; i < n; i++) {
if (coins[i] > smallest) break; //欸湊不到
smallest += coins[i];
}
cout << smallest << "\n";
}
先做再說,後果等等處理
給你一個數列,可以從左至右取數字,問在
過程中數字和不小於零的情況下,最多可以
拿取幾個數字?
| 4 | -4 | 1 | -3 | 1 | -3 |
|---|
總和:0
先把所有數字都加
發現總和 < 0 的時候放棄最小的數字
| 4 | -4 | 1 | -3 | 1 | -3 |
|---|
總和:1
先把所有數字都加
發現總和 < 0 的時候放棄最小的數字
| 4 | -4 | 1 | -3 | 1 | -3 |
|---|
總和:-2
先把所有數字都加
發現總和 < 0 的時候放棄最小的數字
| 4 | -4 | 1 | -3 | 1 | -3 |
|---|
總和:2
先把所有數字都加
發現總和 < 0 的時候放棄最小的數字
| 4 | -4 | 1 | -3 | 1 | -3 |
|---|
總和:3
先把所有數字都加
發現總和 < 0 的時候放棄最小的數字
| 4 | -4 | 1 | -3 | 1 | -3 |
|---|
總和:0
先把所有數字都加
發現總和 < 0 的時候放棄最小的數字
ans:5
#include<bits/stdc++.h>
using namespace std;
int main(){
priority_queue<long long,vector<long long>,greater<long long>> pq;
//pq維護代價最大的藥水
int n;
cin >> n;
long long hp = 0, cnt = 0;
while(n--) {
int k;
cin >> k;
hp += k;
cnt++;
pq.push(k);
while(hp < 0){//生命少於 0 開始反悔
cnt--;
hp -= pq.top();
pq.pop();
}
}
cout << cnt << endl;
}code
簡報做不玩了這個當作業吧
dynamic programming
動態規劃
簡單來說
把大問題拆成小問題
然後把小問題的答案記下來,避免重複計算
好抽象 來點飯粒
每次選字都是前墜河
一個陣列所有前方的元素和
| 1 | 5 | 2 | 4 | 3 |
| 1 | 6 | 8 | 12 | 15 |
原陣列
前綴和
如果每個元素都要重新加一遍
加法次數
1
2
3
4
5
第 i 個元素需要 i + 1 次
O(N²)
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
pre[i]+=a[j];
#include<bits/stdc++.h>
using namespace std;
signed main() {
int n;
cin >> n;
int a[n],pre[n];
for (int i = 0; i < n; i++) cin >> a[i];
pre[0] = a[0];
for (int i = 1; i < n; i++) pre[i] = pre[i - 1] + a[i];
for (int i = 0; i < n; i++) cout << pre[i] << " ";
}
#include<bits/stdc++.h>
using namespace std;
signed main() {
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 1; i < n; i++) a[i] += a[i - 1];
for (int i = 0; i < n; i++) cout << a[i] << " ";
}// 其實不用多開一個#include<bits/stdc++.h>
using namespace std;
signed main(){
int n, l, r;
cin >> n >> l >> r;
vector<int> v(n);
for (int i = 0; i < n; i++) cin >> v[i];
for (int i = 0; i < n; i++) v[i] += v[i - 1];//前綴和
cout << v[r] - (l?v[l-1]:0) << "\n";
}
廢事樹列
之前遞迴講到的東東
每次計算 fibo(n) 都會重複計算 fibo(n-1) 和 fibo(n-2)
O(2ⁿ)
#include <bits/stdc++.h>
using namespace std;
vector<int> dp(30);
int main() {
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i < dp.size(); i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
int q;
while (cin >> q) {
cout << dp[q] << '\n';
}
}喔他其實是背包之後才講
反正我先把 AC 扣丟這
#include <iostream>
#include <vector>
using namespace std;
const int INF = 1e9;
int main() {
int n, x;
cin >> n >> x;
vector<int> c(n); // 每種硬幣面額
for (int j = 0; j < n; ++j) {
cin >> c[j];
}
vector<int> amount(x + 1); // amount[i] 表示湊出金額 i 需要的最少硬幣數
amount[0] = 0;
// 計算每個金額所需的最少硬幣數
for (int i = 1; i <= x; ++i) {
amount[i] = INF; // 預設
for (int j = 0; j < n; ++j) {
if (i - c[j] >= 0) {
// 可以用這個硬幣湊
amount[i] = min(amount[i], amount[i - c[j]] + 1);
// 用這個硬幣 + 之前湊出 (i - c[j]) 的最少硬幣
}
}
}
int answer = amount[x];
if (answer == INF) answer = -1;
cout << answer << "\n";
}