貪心演算法 --- 例題1.活動安排問題
阿新 • • 發佈:2021-12-21
一.問題描述
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; }
執行結果:
參考畢方明老師《演算法設計與分析》課件.
歡迎大家訪問個人部落格網站---喬治的程式設計小屋,和我一起努力吧!