1. 程式人生 > >【差分】會場安排問題

【差分】會場安排問題

很久很久以前的東西了。。

那時候是弱菜中的弱菜(現在是弱菜),這篇文章我也不改什麼。。

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

會場數。)

«程式設計任務:對於給定的k個待安排的活動,程式設計計算使用最少會場的時間表。«資料輸入:由檔案input.txt給出輸入資料。第一行有1 個正整數k,表示有k個待安排的活動。接下來的k行中,每行有2個正整數,分別表示k個待安排的活動開始時間和結束時間。時間以0 點開始的分鐘計。«結果輸出:將程式設計計算出的最少會場數輸出到檔案output.txt。輸入檔案示例 輸出檔案示例input.txt  output.txt5              31 2312 2825 3527 80

36 50

(CJMXHLXW)

這道題是我們考試的一道題,當時我看到就懵逼,考試考的是貪心分治,可是我考試的時候做別的難題去了,越做越煩,做這題時貪心都沒貪出來,結果那次考試爆0,尷尬了尷尬

考試完題目總是要講解的嘛,黃司機A掉了這道題,這道題先是他上去講解貪心演算法,時間複雜度為O(n^2)。

第二天,wen大神又來為我們講解了某種高階演算法——好像提到了差分陣列偷笑,我居然聽懂了驚訝。而且還心血來潮,寫了個題解。=_=

首先搞懂這個“差分陣列”,我們用到的主要功能就是在某個集合裡,在[L,R]這個區間內,把每個數都加上k,用我們普通的演算法肯定是for一遍,這樣如果有n個數,要m次操作,那麼時間複雜度就是O(mn),而這道題的範圍n有10^8,m有10^4,顯然這是不行的。這裡wen大神介紹了一種新的資料結構——差分陣列。把[L,R]區間裡都加上k,只需要把a[L]加上k,再把a[R+1]減去k就行了,當時聽了也不懂,這樣後求L~R區間的和不是隻加了1個k嗎。原來求和的sum[i]加到a[L]時,值為k,加了a[R+1]後,又變為0,我們就可以理解為[L,R]區間裡都加了k。還有這種操作?生氣

驚訝當然這道題集合的範圍有10^8,而我們不可能開個10^8的陣列,所以我們可以先sort一遍,然後把集合壓縮,把每個數取第一次出現的次數,就拿樣例來說吧,sort後為1  12 23 25 27 28 35 36 50 80,直接對應1,2,3,4,5,6,7,8,9,10,我們直接按之前說的操作,把數改成下標就行了。

好了,上程式碼

#include <iostream>
#include <map>
using namespace std;
int a[100010],b[100010],c[100010],d[100010],n,now,sum,Max;
map<int,int>e;
int main(){
	freopen("sche.in","r",stdin);
	freopen("sche.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
       scanf("%d%d",&a[i],&b[i]);
       c[2*i-1]=a[i];
       c[2*i]=b[i];
    }
    sort(c+1,c+2*n+1);
    for(int i=1;i<=2*n;i++)
       if(!e[c[i]])
         e[c[i]]=++now;
    for(int i=1;i<=n;i++)
       d[e[a[i]]]++,
       d[e[b[i]]]--;
    for(int i=1;i<=now+1;i++)
       sum+=d[i],
       Max=max(Max,sum);
    cout<<Max;
	fclose(stdin);
	fclose(stdout);
	//system("pause");
	return 0;
}