# 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; } ```