1. 程式人生 > 其它 >第二部分 基礎演算法 --> 第六章 貪心演算法

第二部分 基礎演算法 --> 第六章 貪心演算法

目錄

貪心演算法

1422:【例題1】活動安排

【題目描述】
設有 n 個活動的集合 E={1,2,…,n},其中每個活動都要求使用同一資源,
如演講會場等,而在同一時間內只有一個活動能使用這一資源。
每個活動 i 都有一個要求使用該資源的起始時間 si 和一個結束時間 fi,且 si<fi。
如果選擇了活動 i,則它在半開時間區間 [si,fi) 內佔用資源。
若區間 [si,fi) 與區間 [sj,fj) 不相交, 則稱活動 i 與活動 j 是相容的。
也就是說,當 si ≥fj 或 sj ≥fi 時,活動 i 與活動 j 相容。
選擇出由相互相容的活動組成的最大集合。

【輸入】
第 1 行一個整數 n(n≤1000),接下來 n 行,每行兩個整數 si 和 fi。

【輸出】
輸出儘可能多的互相相容的活動個數。

【輸入樣例】

4
1 3
4 6
2 5
1 7

【輸出樣例】

2

【題解】

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
struct T{
    int s,f;
}t[N];
bool cmp(T a, T b){
    return a.f<b.f;
}
int main(){
    int n, cnt=1; scanf("%d", &n);
    for(int i=0; i<n; i++){
        scanf("%d%d", &t[i].s, &t[i].f);
    }
    sort(t, t+n, cmp);
    int end=t[0].f;
    for(int i=1; i<n; i++){
        if(t[i].s>=end){
            cnt++;
            end = t[i].f;
        }
    }
    printf("%d", cnt);
    return 0;
}

1423:【例題2】種樹

【題目描述】
現在我們國家開展新農村建設,農村的住房建設納入了統一規劃,統一建設,政府要求每一住戶門口種些樹。
門口路邊的地區被分割成塊,並被編號成 1..N。
每個部分為一個單位尺寸大小並最多可種一棵樹。
每個居民房子門前被指定了三個號碼B,E,T。
這三個數表示該居民想在 B 和 E 之間最少種 T 棵樹。
當然,B≤E,居民必須記住在指定區不能種多於區域地塊數的樹,所以 T ≤E-B+l。
居民們想種樹的各自區域可以交叉。
你的任務是求出能滿足所有要求的最少的樹的數量,儘量較少政府的支出。

【輸入】
第一行包含資料N,M,區域的個數 (0<N≤30000),房子的數目 (0<m≤5000);

下面的m行描述居民們的需要:B E T,0<B≤E≤30000,T≤E-B+1。

【輸出】
輸出一個數,為滿足所有居民的要求,所需要種樹的最少數量。

【輸入樣例】

9 4
3 5 2
1 4 2
4 6 2
8 9 2

【輸出樣例】

5

【題解】

#include<bits/stdc++.h>
using namespace std;
const int N=3e4+10;
bool used[N];
struct T{
    int s,f,v;
}t[N];
bool cmp(T a, T b){
    return a.f<b.f;
}
int main(){
    int n,m,ans=0; scanf("%d%d", &n, &m);
    for(int i=0; i<m; i++){
        scanf("%d%d%d", &t[i].s, &t[i].f, &t[i].v);
    }
    sort(t, t+m, cmp);
    for(int i=0; i<m; i++){
        int cnt=0;
        for(int j=t[i].s; j<=t[i].f; j++){
            if(used[j]) cnt++;
        }
        if(cnt>=t[i].v) continue;
        for(int j=t[i].f; j>=t[i].s; j--){
            if(!used[j]){
                used[j]=1; cnt++; ans++;
            }
            if(cnt==t[i].v) break;
        }
    }
    printf("%d\n", ans);
    return 0;
}

1426:【例題5】智力大沖浪

【題目描述】
小偉報名參加中央電視臺的智力大沖浪節目。
本次挑戰賽吸引了眾多參賽者,主持人為了表彰大家的勇氣,先獎勵每個參賽者 m 元。
先不要太高興!因為這些錢還不一定都是你的。
接下來主持人宣佈了比賽規則:
首先,比賽時間分為 n 個時段 (n≤500),它又給出了很多小遊戲,
每個小遊戲都必須在規定期限 ti 前完成 (1≤ti≤n)。
如果一個遊戲沒能在規定期限前完成,則要從獎勵費m元中扣去一部分錢 wi,wi 為自然數,
不同的遊戲扣去的錢是不一樣的。
當然,每個遊戲本身都很簡單,保證每個參賽者都能在一個時段內完成,而且都必須從整時段開始。
主持人只是想考考每個參賽者如何安排組織自己做遊戲的順序。
作為參賽者,小偉很想贏得冠軍,當然更想贏取最多的錢!
注意:比賽絕對不會讓參賽者賠錢!

【輸入】
輸入共 4 行。
第一行為 m,表示一開始獎勵給每位參賽者的錢;
第二行為 n,表示有 n個小遊戲; 第三行有 n 個數,分別表示遊戲 1~n 的規定完成期限;
第四行有 n 個數,分別表示遊戲 1~n 不能在規定期限前完成的扣款數。

【輸出】
僅 1 行。表示小偉能贏取最多的錢。

【輸入樣例】

10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10

【輸出樣例】

9950

【資料範圍】n≤500,1≤ti≤n

【題解】

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
bool vis[N];
struct T{
    int t,w;
}t[N];
bool cmp(T a, T b){
    if(a.w!=b.w) return a.w>b.w;
    return a.t<b.t;
}
int main(){
//    freopen("data.in", "r", stdin);
    int m,n; scanf("%d%d", &m, &n);
    for(int i=0; i<n; i++) scanf("%d", &t[i].t);
    for(int i=0; i<n; i++) scanf("%d", &t[i].w);
    sort(t, t+n, cmp);
    int ans=0;
    for(int i=0; i<n; i++){
        bool flag=0;
        for(int j=t[i].t; j>=1; j--){
            if(!vis[j]){
                vis[j]=1; flag=1; break;
            }
        }
        if(!flag){
            ans+=t[i].w;
        }
    }
    printf("%d\n", m-ans);
    return 0;
}