# greedy 經典問題
主要說一些greedy的經典問題
=_=
## 排程問題/活動選擇問題(activity selection problem)
例題
https://judge.tcirc.tw/ShowProblem?problemid=d045
給一些活動的起始跟結束時間
問最多可參加到的活動數為多少個
### 講解
其實可以換一個方式理解題目:
**如何在數線上找到最多條不重疊的線段**
感覺就是找最短的
其實不是
會有假解的
但是想法換成這樣:
**如果有一個線段的右端點(右界)是現有線段裡面最小的(最左邊),則最優解裡面一定會有這個線段**
這有點抽象
用筆畫畫看就會有感覺
**那就找右端點最小的(結束時間小的排到結束時間大的/最早結束就排前面)**
->排序!
**一句話總結:<font color="##FF0000">先結束的排在前面</font>**
看範例比較好理解
### 範例練習
AP325:d045: 例題 P-4-4. 幾場華山論劍activity selection
https://judge.tcirc.tw/ShowProblem?problemid=d045)
解1:用pair AC(23ms, 3.9MB)
```cpp=
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define inf 2e18
#define maxn 100005
#define mod 1000000007
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
vector<pair<int,int>>vec; //紀錄活動開始時間跟結束時間
int n;
cin>>n;
for(int i=0;i<n;i++){
int start,finish;
cin>>start>>finish;
vec.push_back({finish,start}); //小心 pair的排序是先排begin()再排end()->begin()放結束時間,end()放開始時間
}
sort(vec.begin(),vec.end()); //排序找右端點(結束時間)最小的
int finish_time=vec[0].first; //找結束最早的,finish_time是更新目前參加的活動中最晚的結束時間
int cnt=1; //不論如何至少有一個
for(auto a:vec){
if(a.second>finish_time){ //剩下活動中的開始時間至少要超過finish_time
cnt++;
finish_time=a.first; //更新剩下活動的開始時間的下限
}
}
cout<<cnt;
}
```
解1.5: AC(23ms, 3.9MB)
```cpp=
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define inf 2e18
#define maxn 100005
#define mod 1000000007
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
vector<pair<int,int>>vec;
int n;
cin>>n;
for(int i=0;i<n;i++){
int start,finish;
cin>>start>>finish;
vec.push_back({finish,start});
}
sort(vec.begin(),vec.end());
int finish_time=-1; //這裡變-1
int cnt=0; //這裡變0
for(auto a:vec){
if(a.second>finish_time){
cnt++;
finish_time=a.first;
}
}
cout<<cnt;
}
```
解2:用struct AC(22ms, 1.8MB)
我是覺得不要啦
沒那麼好用
而且很醜
(也可能是我寫很醜)
```cpp=
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define inf 2e18
#define maxn 100005
#define mod 1000000007
struct act{
int start,finish;
}vec[maxn];
bool cmp(act a,act b){
return a.finish<b.finish;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>vec[i].start>>vec[i].finish;
}
sort(vec,vec+n,cmp);
int finish_time=vec[0].finish;
int cnt=1;
for(int i=1;i<n;i++){
if(vec[i].start>finish_time){
cnt++;
finish_time=vec[i].finish;
}
}
cout<<cnt;
}
```
洛谷:P1803 凌乱的yyy/线段覆盖
https://www.luogu.com.cn/problem/P1803
```cpp=
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define inf 2e18
#define maxn 100005
#define mod 1000000007
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
vector<pair<int,int>>vec;
int n;
cin>>n;
for(int i=0;i<n;i++){
int start,finish;
cin>>start>>finish;
vec.push_back({finish,start});
}
sort(vec.begin(),vec.end());
int finish_time=vec[0].first;
int cnt=1;
for(auto a:vec){
if(a.second>=finish_time){ //這題要用等於!
cnt++;
finish_time=a.first;
}
}
cout<<cnt;
}
```