貪心題集
活動安排
題目描述
設有 個活動的集合 ,其中每個活動都要求使用同一資源,如演講會場等,而在同一時間內只有一個活動能使用這一資源。每個活動 都有一個要求使用該資源的起始時間 和一個結束時間 ,且 。如果選擇了活動 ,則它在時間區間 內佔用資源。若區間 與區間 不相交,則稱活動 與活動 是相容的。也就是說,當 或 時,活動 與活動 相容。選擇出由互相相容的活動組成的最大集合。
思路
按結束時間進行排序,先完成的先貪
程式碼
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> using namespace std; #define int long long const int manx = 1e5; struct node{ int l,r; }e[manx]; int cmp(node a,node b){ return a.r < b.r; } char obuf[1<<24], *O=obuf; void print(int x) { if(x > 9) print(x / 10); *O++ = x % 10 + '0'; } int n; main(){ cin >> n; for(int i = 1;i <= n; i++){ cin>>e[i].l>>e[i].r; } sort(e+1,e+1+n,cmp); int top = 0,ans = 0; for(int i = 1;i <= n ; ++i){ if(e[i].l >= top) { ans++; top = e[i].r; } continue; } print(ans),*O++ = '\n'; fwrite(obuf, O-obuf, 1, stdout); }
種樹
題目描述
某條街被劃為 \(n\) 條路段,這 \(n\) 條路段依次編號為 \(1...n\) 。每個路段最多可以種一棵樹。現在居民們給出了 \(h\) 組建議,每組建議包含三個整數 \(b,e,t\),表示居民希望在路段 \(b\) 到 \(e\) 之間至少要種 \(t\) 棵樹。這些建議所給路段的區間可以交叉。請問:如果要滿足所有居民的建議,至少要種多少棵樹。
思路
以後綴排序,把樹種在末尾,每次更改時掃一遍已種的棵樹,再在末尾種剩餘的樹,存在小的區間已經佔有,大區間尾端被小區見更新,所以需要判斷是否重新劍術
程式碼
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> using namespace std; #define int long long const int manx = 1e6; char obuf[1<<24], *O=obuf; void print(int x) { if(x > 9) print(x / 10); *O++ = x % 10 + '0'; } struct node{ int l,r,s; }e[manx]; int cmp(node a,node b){ return a.r < b.r;//結束時間排序 } int n,m,v[manx]; main(){ cin >> n>>m; for(int i = 1;i <= m; i++){ cin>>e[i].l >>e[i].r>>e[i].s; } sort(e+1,e+1+m,cmp); int top = 0,ans = 0; for(int i = 1;i <= m; i++){ int js = 0; for(int j = e[i].l ; j <= e[i].r ;j ++){ if(v[j] == 1) js++; } if(js < e[i].s){ for(int j = e[i].r ; j >= e[i].l ; j--){ if(v[j] == 0) { v[j] = 1;//存在小區間已經佔有,大區間尾端被小區見更新,所以需要判斷是否重新劍術 if(++js == e[i].s) break; } } } else{ continue; } } for(int i = 1;i <= n; i++){ if(v[i] == 1) ans++; } print(ans),*O++ = '\n'; fwrite(obuf, O-obuf, 1, stdout); }
排水裝置
題目描述
長 \(L\) 米,寬 \(W\) 米的草坪裡裝有 \(n\) 個澆灌噴頭。每個噴頭都裝在草坪中心線上(離兩邊各 \(\frac{W}{2}\) 米)。我們知道每個噴頭的位置(離草坪中心線左端的距離),以及它能覆蓋到的澆灌範圍。
請問:如果要同時澆灌整塊草坪,最少需要開啟多少個噴頭?
思路
\[\sqrt{r^2 - {(\frac{W}{2})}^2} \]顯然超過寬度 \(W\)的長度對答案有勾股定理的的範圍貢獻,因此可以將每個點都將其範圍最大化,
程式碼
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> using namespace std; const int manx = 1e6; double w; int n/*,n*/,t,l,js; double s ; double r ; struct node{ double x,y; }e[manx]; bool cmp(node a,node b){ return a.x < b.x; } int main(){ cin>>t; while(t--){ cin>>n>>l>>w; js = 0; for(int i = 1;i <= n; i++){ cin>>s>>r; if(r <= w/2) continue; js++; e[js].x = s - sqrt(r *r - (w/2)*(w/2)); e[js].y = s + sqrt(r *r - w*w*0.25); } sort(e+1,e+1+js,cmp); int ans = 0,flag = 1,i = 1; double top = 0; while(top < l){ ans++; double s = top; for( ;e[i].x<=s&&i <= js; i++) top = max(top,e[i].y); if(s == top && s < l){ cout<<"-1"<<endl; flag = 0; break; } } if(flag) cout<<ans<<endl; } return 0; }
加工生產排程
題目描述
某工廠收到了 個產品的訂單 \(n\),這 \(n\) 個產品分別在 A、B 兩個車間加工,並且必須先在 A 車間加工後才可以到 B 車間加工。
某個產品\(i\) 在 A,B 兩車間加工的時間分別為 \(A_i\) \(B_i\)。怎樣安排這 個產品的加工順序,才能使總的加工時間最短。
這裡所說的加工時間是指:從開始加工第一個產品到最後所有的產品都已在 A,B 兩車間加工完畢的時間。
思路
對於時間劃分來說,為了達到目標,儘可能的讓\(A,B\) 的休息時間儘量的少,那麼將其劃分為每個決策,每個決策都保證 \(A,B\) 的時間最小,因此可得貪心
程式碼
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int manx = 1e5 + 10;
struct node{
int s,id,iid;
}m[manx];
int cmp(node a,node b){
return a.s < b.s;
}
int n,a[manx],x[manx],y[manx];
int main(){
cin >> n;
for(int i = 1;i <= n; i++){
cin>>x[i];
}
for(int i = 1;i <= n; i ++){
cin>>y[i];
}
for(int i = 1;i <= n; i++){
m[i].s = min(x[i],y[i]);
//cout<<m[i].s<<endl;
if(x[i] == m[i].s) m[i].id = 0;
else m[i].id = 1;
m[i].iid = i;
}
sort(m+1,m+1+n,cmp);
//for(int i = 1;i <= n; i++) cout<<m[i].s <<" ";
int top = 0,till = n + 1;
for(int i = 1;i <= n; i++){
if(m[i].id == 0){
a[++top] = m[i].iid;
}
if(m[i].id == 1){
a[--till] = m[i].iid;
}
}
int k = 0,t = 0;
for(int i = 1;i<=n; i++){
k+=x[a[i]];
//cout<<k<<" "<<i<<endl;
if(t<k) t = k;
t += y[a[i]];
//cout<<t<<" "<<i<<endl;
}
cout<<t<<endl;
for(int i = 1;i <= n; i++) cout<<a[i]<<" ";
}
5.智力大沖浪
題目描述
小偉報名參加中央電視臺的智力大沖浪節目。本次挑戰賽吸引了眾多參賽者,主持人為了表彰大家的勇氣,先獎勵每個參賽者 \(m\) 元。先不要太高興!因為這些錢還不一定都是你的?!接下來主持人宣佈了比賽規則:
首先,比賽時間分為 \(n\) 個時段,它又給出了很多小遊戲,每個小遊戲都必須在規定期限 \(t_i\) 前完成。如果一個遊戲沒能在規定期限前完成,則要從獎勵費 \(m\) 元中扣去一部分錢 \(w_i\) ,\(w_i\) 為自然數,不同的遊戲扣去的錢是不一樣的。當然,每個遊戲本身都很簡單,保證每個參賽者都能在一個時段內完成,而且都必須從整時段開始。主持人只是想考考每個參賽者如何安排組織自己做遊戲的順序。作為參賽者,小偉很想贏得冠軍,當然更想贏取最多的錢!注意:比賽絕對不會讓參賽者賠錢!
思路
顯然是先做扣錢多的,其次是少的,在扣錢多的同一時間裡,儘量的讓大時間往後去,這就是貪心的思路
程式碼
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
#define int long long
const int manx = 1e6;
struct node{
int tim,m;
}e[manx];
int cmp(node a,node b){
if(a.m == b.m)
return a.tim > b.tim;
return a.m > b.m;
}
int n,m,vis[manx],s[manx];
main(){
cin>>m>>n;
for(int i = 1;i <= n; i++){
cin>>e[i].tim;
}
for(int i = 1;i <= n; i++){
cin>>e[i].m;
}
sort(e+1,e+1+n,cmp);
for(int i = 1;i <= n; i++){
while(vis[e[i].tim]) e[i].tim--;
if(e[i].tim) vis[e[i].tim] = 1;
else m -= e[i].m ;
}
cout<<m<<endl;
}