2012-09-03 16:43:44Morris

[ZJ][二分Greedy] d830. 暗門2

內容 :

在一個其大無比的空間裡,有 n 個房間相鄰著,譬如第5間的左側是第4間、右側是第6間

現在有 m 個人分別不同的房間。

但因為有些房間太空,有些則是太擠,所以我們要做一些調整,

使得每個房間裡面的人數一樣多。為了達到節能減炭的目的,

我們先假定一個k值,每個人的移動距離都不超過k,接著要求出最小的這個k

移動距離的計算方式是:某人從第i移動到第j間,則距離為 |i-j|

輸入說明 :

輸入包含多比測試資料。

第一行給定兩個整數n,m (m為n的倍數)。接著第二行有m個整數,並用空格隔開

分別表示這m個人在哪一個房間裡面。

0 <= n <= m <= 100000

輸出說明 :

輸出一個整數,代表題目敘述中所要求的k值。

範例輸入 :help

4 8
1 2 3 4 2 3 4 4

範例輸出 :

1

提示 :

出處 :

(管理:shik)

題意就不講解了, 這題的解法是 二分搜尋 k, 然後把每一個人的所在房間做一個排序,
接著當我們枚舉 k 時, 對於每一個人會產生一個可移動的區間 [ai-k, ai+k],
只要我們檢查 1~n 每個房間是不是都能包涵 m/n 個這樣的區間, 就行了。
這一個部份你可以從程式碼看出來。

那也有人會想問在檢查的時候, 會不會有問題 ?
你仔細想想, 每個區間的長度都一樣, 我先挑位於前面的區間, 不會導致後面的區間錯誤,
因為當他區間長度一樣, 就不會發生問題, 所涵蓋的區間只會多, 不會少。



#include <stdio.h>

#include <stdlib.h>
#include <algorithm>
using namespace std;
int a[100000], n, m, nm;
int test(int k) {
    static int i, j, cnt;
    for(i = 1, j = 0; i <= n; i++) {
        cnt = 0;
        while(j < m && cnt < nm && a[j]-k <= i && i <= a[j]+k) {
            cnt++, j++;
        }
        if(cnt != nm)   return 0;
    }
    return 1;
}
int main() {
    int i;
    while(scanf("%d %d", &n, &m) == 2) {
        for(i = 0; i < m; i++)
            scanf("%d", &a[i]);
        sort(a, a+m);
        nm = m/n;
        int l = 0, r = n/2;
        while(l < r) {
            int m = (l+r)/2;
            if(test(m))
                r = m;
            else
                l = m+1;
        }
        printf("%d\n", r);
    }
    return 0;
}