1. 程式人生 > 實用技巧 >貪心題集

貪心題集

活動安排

題目描述

設有 個活動的集合 ,其中每個活動都要求使用同一資源,如演講會場等,而在同一時間內只有一個活動能使用這一資源。每個活動 都有一個要求使用該資源的起始時間 和一個結束時間 ,且 。如果選擇了活動 ,則它在時間區間 內佔用資源。若區間 與區間 不相交,則稱活動 與活動 是相容的。也就是說,當 或 時,活動 與活動 相容。選擇出由互相相容的活動組成的最大集合。

思路

按結束時間進行排序,先完成的先貪

程式碼

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