1. 程式人生 > 其它 >貪心演算法 --- 例題1.活動安排問題

貪心演算法 --- 例題1.活動安排問題

一.問題描述

n個活動的集合E={1,2,…,n},在某一時間內要獨佔使用某個資源。每個活動i使用資源的起始時間為Si,終止時間為Fi。

活動i和活動j相容:是指[Si,Fi)與[Sj,Fj)不相交,即:Sj>=Fi 或Si>=Fj, 要求儘可能多地安排活動。即從活動集合E中選出最大相容活動子集。

二.解題思路

思路:最早結束的活動,優先安排。對f1,f2,…,fn從小到大排序 , 時間O(n log n);
即將n個活動按照結束時間非降序排列,依次考慮活動i,若i與已選擇的活動相容,則將其加入相容活動子集.

Fj總是當前活動集合中結束最晚的活動
一旦Si>=Fj,則活動i和活動j相容,將活動i加入A中, i取代j成為最近加入的活動
直觀上,該演算法每次總是選取最早完成時間的活動,這樣就為安排其它活動留下儘可能多的時間,從而能安排更多的活動。

證明上述貪心演算法一定能得到最優解:(略) 數學歸納法得證.

程式碼如下:

// 活動安排問題
// 貪心演算法
// 策略:每選一個之後能給後面的留更多的時間(效果:按結束時間排序)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10010;
struct Node
{
    int begin, end;
    int index;  //記錄活動起始編號
}node[maxn];
bool cmp(Node a, Node b)
{
    return a.end < b.end;
}
int main()
{
    int t, n;  //t組資料,每組n個活動
    cout<<"請輸入資料組數:";
    scanf("%d", &t);
    while(t--)
    {
        cout<<"請輸入活動個數:";
        scanf("%d", &n);
        cout<<"請輸入每個活動的起始時間:"<<endl;
        for(int i=0; i<n; ++i)  //輸入區間,並作簡單處理
        {
            printf("活動%d起始時間為:", i);
            scanf("%d %d", &node[i].begin, &node[i].end);
            node[i].index = i;
            node[i].end++; //將區間變成左閉右開,便於處理
        }
        sort(node, node+n, cmp); //將區間按照右端點排序,右端點小的在前面
        int ans = 0;
        int pos = 0;
        vector<int> select;
        for(int i=0; i<n; ++i)
        {
            if(node[i].begin>=pos)
            {
                ans++;
                pos = node[i].end;
                select.push_back(node[i].index);
            }
        }
        printf("最多安排%d個活動\n", ans);
        printf("選中的活動為:");
        for(int x:select) printf("%d:[%d,%d] ",x, node[x].begin, node[x].end-1);
        cout<<endl;
    }
    system("pause");
    return 0;
}

執行結果:

參考畢方明老師《演算法設計與分析》課件.

歡迎大家訪問個人部落格網站---喬治的程式設計小屋,和我一起努力吧!