假設要在足夠多的會場里安排一批活動,並希望使用盡可能少的會場。設計一個有效的 貪心算法進行安排。(這個問題實際上是著名的圖着色問題。若將每一個活動作為圖的一個 頂點,不相容活動間用邊相連。使相鄰頂點着有不同顏色的最小着色數,相應於要找的最小 會場數。)
輸入格式:
第一行有 1 個正整數k,表示有 k個待安排的活動。 接下來的 k行中,每行有 2個正整數,分別表示 k個待安排的活動開始時間和結束時間。時間 以 0 點開始的分鍾計。
輸出格式:
輸出最少會場數。
輸入樣例:
5 1 23 12 28 25 35 27 80 36 50
輸出樣例:
3
算法:
錯誤解法:
按照結束時間排序,然后開始放活動,這樣貪心可以使每次放的活動最多。
這樣做是錯的,這樣只能保證第一次放的活動是最多的,但是具備有后效性,不能使全局最優。網上的很多解法都是這個,是錯誤的。
比如數據:
6 90 98---1 8 32----2 18 48---3 16 82---4 83 84---5 39 89---6
這組數據的答案是3,我們把活動按照1-n編號,那么分別用三個會場裝(2, 6)、(4, 5)、(3, 1),就能完成任務,答案是3。
但是如果按照貪心排結束時間的做法,答案是4,在第一次拿的時候我們拿了很多,3個,但是這也導致后面的活動都不得不單獨開一個會場,導致答案為4,不是最優解。這也就是典型的局部最優不能帶來全局最優。
附上錯誤代碼:
#include <iostream> using namespace std; typedef struct { int start; int end; }Event; int main(){ int k; //表示有 k個待安排的活動 cin>>k; Event event[k+1]; for(int i=1;i<=k;i++){ cin>>event[i].start>>event[i].end; //活動開始時間和結束時間 } for(int i=1;i<=k;i++){ //event數組按活動的結束時間從小到大排序 int min=event[i].end,min_id=i; //冒泡 for(int j=i+1;j<=k;j++){ if(event[j].end<min) { min = event[j].end; min_id = j; } } swap(event[i],event[min_id]); } int room[k+1]={0}; // 會場,room[i]記錄活動結束的時間,即表示第i個會場開始空閑的時間 // 初始化為0,表示未使用,若不是0則代表該會場已經被使用過 for(int i=1;i<=k;i++){ for(int j=1;j<=k;j++){ if(room[j]<=event[i].start) { room[j]=event[i].end; break; } } } int count=0; //統計room數組非0單元個數,即最小使用數 for(int i=1;i<=k;i++){ if(room[i]==0) break; count++; } cout<<count<<endl; }
稍微改一下就好
正確代碼:
#include <iostream> using namespace std; typedef struct { int start; int end; }Event; int main(){ int k; //表示有 k個待安排的活動 cin>>k; Event event[k+1]; for(int i=1;i<=k;i++){ cin>>event[i].start>>event[i].end; //活動開始時間和結束時間 } for(int i=1;i<=k;i++){ //event數組按活動的開始時間從小到大排序 int min=event[i].start,min_id=i; //冒泡 for(int j=i+1;j<=k;j++){ if(event[j].start<min) { min = event[j].start; min_id = j; } } swap(event[i],event[min_id]); } int room[k+1]={0}; // 會場,room[i]記錄活動結束的時間,即表示第i個會場開始空閑的時間 // 初始化為0,表示未使用,若不是0則代表該會場已經被使用過 for(int i=1;i<=k;i++){ for(int j=1;j<=k;j++){ if(room[j]<=event[i].start) { room[j]=event[i].end; break; } } } int count=0; //統計room數組非0單元個數,即最小使用數 for(int i=1;i<=k;i++){ if(room[i]==0) break; count++; } cout<<count<<endl; }
下圖重疊的地方表示活動之間不兼容,即不能在同一會場進行
最大重疊數 = 最小會場數