貪心算法解決活動安排問題

4.2 活動安排問題
設有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相 容。 活動安排問題就是在所給的活動集合中選出最大的相容 活動子集合。
輸入: 測試數據的第一行是正整數n (n≤100),表示活動數,後跟n 行,每行的三個數分別表示活動的 編號、開始時間、結束時間,數據 之間由一個空格分隔開。 輸出: 輸出選中的活動編號(或選中 的活動個數)。
輸入樣例:
11
1 1 4
2 3 5
3 0 6
4 5 7
5 3 8
6 5 9
7 6 10
8 8 11
9 8 12
10 2 13
11 12 14
輸出樣例:
1 4 8 11
代碼實現:

//ACM貪心算法——活動安排問題
#include <iostream>
#include <algorithm>
using namespace std;
struct ActionInfo {                 //單個活動的信息節點
    int index;                      //活動編號
    int startTime;                  //活動開始時間
    int endTime;                    //活動結束時間
};
bool cmp(const ActionInfo &a, ActionInfo &b);
int main()
{
    int actionsGroups = 0;                          //所有的活動的組數
    cin >> actionsGroups;
    ActionInfo *act = new ActionInfo[actionsGroups];//開闢活動數組
    for (int i = 0; i < actionsGroups; i ++) {
        //輸入所有活動的信息
        cin >> act[i].index >> act[i].startTime 
            >> act[i].endTime;
    }
    //對所有活動按照endtime升序排序
    sort(act, act + actionsGroups, cmp);
    //貪心算法:只要下一個活動的開始時間在當前活動結束時間之後則這兩個活動相容
    //把此活動加入符合條件的集合
    int currentAction = 0, count = 0;               //當前符合要求的活動
    int notConflictActionsIndex[100];               //此處用一個常量來定義
    notConflictActionsIndex[count] = act[0].index;
    for (int j = 1; j < actionsGroups; j ++) {
        if (act[j].startTime >= act[currentAction].endTime) {
            currentAction = j;
            notConflictActionsIndex[++count] = act[j].index;    //記下不衝突活動的編碼
        }
    }
    //輸出
    for (int k = 0; k <= count; k ++) {
        cout << notConflictActionsIndex[k] << ' ';
    }
    delete[] act;                                   //釋放資源
    system("pause");
    return 0;
}
bool cmp(const ActionInfo &a, ActionInfo &b) {
    //比較函數,作爲sort的第三個參數,實現升序排序
    if (a.endTime <= b.endTime) {
        return true;
    }
    return false;
}

總結:
1數據結構:
struct action {
int index; //活動的編號
int f; //結束時間
};
2排序:按活動的結束時間升序排序 排序比較因子:
if (a.f<=b.f) return true;
return false; } 使用標準模板庫函數排序: sort(a, a+n, cmp);
此處推薦一片具體介紹C++ sort函數的文章:
STL sort 函數內部的實現 爲什麼會比你寫的快
3 貪心選擇:優先選擇結束時間早的
4 活動安排問題就是要在所給的活動集合中選出最大 的相容活動子集合,是可以用貪心算法有效求解的很好 例子。 該問題要求高效地安排一系列爭用某一公共資源的 活動。 貪心算法提供了一個簡單、漂亮的方法使得儘可能 多的活動能兼容地使用公共資源。
4.3 貪心算法
貪心算法是一種在每一步選擇中都採取在當前狀態 下最好或最優的選擇,希望得到結果是最好或最優的算法。 貪心算法是一種能夠得到某種度量意義下的最優解的 分級處理方法,通過一系列的選擇得到一個問題的解,而 它所做的每一次選擇都是當前狀態下某種意義的最好選擇。 即希望通過問題的局部最優解求出整個問題的最優解。 這種策略是一種很簡潔的方法,對許多問題它能產生 整體最優解,但不能保證總是有效,因爲它不是對所有問 題都能得到整體最優解。 利用貪心策略解題,需要解決兩個問題: (1)該題是否適合於用貪心策略求解; (2)如何選擇貪心標準,以得到問題的最優/較優解。
貪心選擇性質: 貪心選擇性質是指所求問題的整體最優解可以通過一 系列局部最優的選擇,即貪心選擇來達到。 這是貪心算法可行的第一個基本要素,也是貪心算法 與動態規劃算法的主要區別。 (1)在動態規劃算法中,每步所做的選擇往往依賴 於相關子問題的解,因而只有在解出相關子問題後,才能 做出選擇。 (2)在貪心算法中,僅在當前狀態下做出最好選擇, 即局部最優選擇,然後再去解出這個選擇後產生的相應的 子問題。
最優子結構: (1) 當一個問題的最優解包含其子問題的最優解時,稱此 問題具有最優子結構性質。 運用貪心策略在每一次轉化時都取得了最優解。問題的最 優子結構性質是該問題可用貪心算法或動態規劃算法求解 的關鍵特徵。 (2) 貪心算法的每一次操作都對結果產生直接影響,而動 態規劃則不是。 貪心算法對每個子問題的解決方案都做出選擇,不能回退; 動態規劃則會根據以前的選擇結果對當前進行選擇,有回 退功能。 動態規劃主要運用於二維或三維問題,而貪心一般是一維 問題。
使用貪心算法求解問題應該考慮如下幾個方面: (1)候選集合A:爲了構造問題的解決方案,有一個候 選集合A作爲問題的可能解,即問題的最終解均取自於 候選集合A。 (2)解集合S:隨着貪心選擇的進行,解集合S不斷擴展, 直到構成滿足問題的完整解。 (3)解決函數solution:檢查解集合S是否構成問題的 完整解。 (4)選擇函數select:即貪心策略,這是貪心法的關鍵, 它指出哪個候選對象最有希望構成問題的解,選擇函數 通常和目標函數有關。 (5)可行函數feasible:檢查解集合中加入一個候選對 象是否可行,即解集合擴展後是否滿足約束條件
以上主要通過老師對貪心算法概念的講解及活動安排的主要解決步驟和貪心策略,對活動安排的代碼進行了實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章