7-2 會場安排問題 (20分)


假設要在足夠多的會場里安排一批活動,並希望使用盡可能少的會場。設計一個有效的 貪心算法進行安排。(這個問題實際上是著名的圖着色問題。若將每一個活動作為圖的一個 頂點,不相容活動間用邊相連。使相鄰頂點着有不同顏色的最小着色數,相應於要找的最小 會場數。)

輸入格式:

第一行有 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;
}

 下圖重疊的地方表示活動之間不兼容,即不能在同一會場進行

最大重疊數 = 最小會場數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM