問題描述:
假設要在足夠多的會場里安排一批活動,並希望使用盡可能少的會場。設計一個有效的貪心算法進行安排(這個問題實際上是著名的圖着色問題。若將每一個活動作為圖的一個頂點,不相容活動間用邊相連。使相鄰頂點着有不同顏色的最小着色數,相應於要找的最小會場數)。
算法設計
對於K個待安排的活動,計算使用最少會場的時間表。
輸入輸出
input.txt
5
1 23
12 28
25 35
27 80
36 50
output.txt
3
先簡單描述我的思路,可能很多人剛開始和我的思路一樣,最終代碼很丑,不過還是簡單敘述一下思路,首先從第一個開始的活動出發,根據該活動的結束時間找到在這個時間之后的第一個活動的開始時間,然后從這個新活動出發再去尋找下一個第一個出現的相容的活動,依次類推,結束第一次遍歷,可以找到一個會場的所有活動,這些活動標記一下,下次不再遍歷。開啟下次遍歷,再找出一個新的會場的所有的活動,直到所有的活動找到會場為止。代碼如下,只可以做參考(太丑)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define M 100 4 int array1[M]; 5 int array2[M]; 6 void arange(int array1[M],int array2[M],int n){ 7 int array3[M]; 8 memset(array3,0,sizeof(array3));//作用是標記該活動是否已經找到會場。 9 int maxnum=0;//需要的會場的個數 10 int t=0;//記錄當前活動的序號 11 int s=0;//每個會場的活動個數 12 int counts=0;//記錄總共標記的活動數 13 while(true){ 14 s=0;//開始新的一個會場的活動 15 t=0; 16 for(int i=t;i<n;i++){ 17 if(array3[i]==1) continue;//已標記的活動直接跳過 18 for(int j=i;j<n;j++){//尋找下一個相容的活動,找到就break 19 s++;//遍歷活動,加一 20 if(s==1){//如果是第一個沒歸入會場的活動標記下來,歸入新會場的第一個活動 21 array3[i]=1; 22 counts++;//已經加入活動的數目加一 23 } 24 if(array2[i]<array1[j] && array3[j]==0){//得到下一個相容的活動。,歸入新的會場,結束循環 25 array3[j]=1; 26 t=j;//更新歸入的活動的坐標,下次從這個活動向后找 27 counts++;//已經加入會場的數目加一 28 break; 29 } 30 } 31 } 32 maxnum++;//會場的數目加一 33 if(counts==n){//所有活動處理完,結束 34 break; 35 } 36 } 37 cout << maxnum; 38 } 39 int main() 40 { 41 int n; 42 cin >> n; 43 memset(array1,0,sizeof(array1));//用戶輸入的活動的起始點 44 memset(array2,0,sizeof(array2));//用戶輸入的活動的結束時間 45 for(int i=0;i<n;i++){ 46 cin >> array1[i] >> array2[i]; 47 } 48 int array3[n]; 49 int array4[n]; 50 memset(array3,0,sizeof(array3));//存儲排序后的活動的起始點 51 memset(array4,0,sizeof(array4));//存儲排序后的活動的終止時間點 52 for(int i=0;i<n;i++){//復制一下起始時間, 53 array3[i]=array1[i]; 54 } 55 sort(array3,array3+n);//所有的活動根據起始時間進行排序用array3和array4進行存儲 56 for(int i=0;i<n;i++){ 57 for(int j=0;j<n;j++) 58 { 59 if(array1[j]==array3[i]){ 60 array4[i]=array2[j]; 61 } 62 } 63 } 64 arange(array3,array4,n); 65 }
下面是書上的參考代碼,很精簡,代碼稍微有點不是好理解,但是思路和我的方法基本一致
具體的思路是:看一活動的開始時間是否大於某一會場的結束時間,如果是就加入該會場中,並更新該會場的結束時間,(如果有多個會場選擇的話,就選最優的那一個,即結束時間最小的)
,如果所有的會場都不滿足,則再新增一個會場,把該活動的結束時間賦予這個新增的會場。
算法的時間復雜度: 設有 n 個活動,使用了k(k<=n)個會場,則時間復雜度為 O(n(k+nlogn))
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 struct point 6 { 7 int t;//活動的端點時間 8 bool f;//true表示活動開始false標志活動結束時間 9 }; 10 bool cmp(point x,point y)//比較時間點的大小 11 { 12 return x.t<y.t; 13 } 14 15 int greedy(vector<point> x) 16 { 17 int max=0,cur=0,n=x.size(); 18 sort(x.begin(),x.end(),cmp);//從小到大排序一下各個活動時間點,排序規則是cmp 19 for(int i=0;i<n;i++) 20 { 21 if(x[i].f)//如果是活動開始時間則加一 22 cur++; 23 else//結束時間減一 24 cur--; 25 if((i==n-1 || x[i].t<x[i+1].t) && cur>max)//此時間點有多個活動進行,而這個重疊活動最大值就是需要的最大會場數 26 max=cur; 27 } 28 return max; 29 } 30 31 int main() 32 { 33 vector<point> x;//容器 34 int n,i; 35 point temp; 36 while(cin>>n,n)//輸入n個活動,即2n個point 37 { 38 for(i=0;i<n;i++) 39 { 40 temp.f=true; 41 cin>>temp.t; 42 x.push_back(temp);//活動開始時間,標志temp.f為true,進入容器 43 temp.f=false; 44 cin>>temp.t; 45 x.push_back(temp);//活動結束時間,標志temp.f為false,進入容器 46 } 47 cout<<greedy(x)<<endl; 48 x.clear();//clear只是把那些元素全部刪除掉,並不是釋放內存 49 } 50 return 0; 51 }