區間移位


問題描述
  數軸上有 n個閉區間 D1,…, Dn。其中區間 Di用一對整數[ aibi]來描述,滿足 ai <  bi。已知這些區間的長度之和至少有10000。所以,通過適當的移動這些區間,你總可以使得他們的“並”覆蓋[0, 10000]——也就是說[0, 10000]這個區間內的每一個點都落於至少一個區間內。
  你希望找一個移動方法,使得位移差最大的那個區間的位移量最小。
  具體來說,假設你將 Di移動到[ ai+ cibi+ ci]這個位置。你希望使得max i | ci|  最小。
輸入格式
  輸入的第一行包含一個整數n,表示區間的數量。
  接下來有n行,每行2個整數ai,  bi,以一個空格分開,表示區間[ aibi]。保證區間的長度之和至少是10000。
輸出格式
  輸出一個數,表示答案。如果答案是整數,只輸出整數部分。如果答案不是整數,輸出時四舍五入保留一位小數。
樣例輸入
2
10 5010
4980 9980
樣例輸出
20
樣例說明
  第一個區間往左移動10;第二個區間往右移動20。
樣例輸入
4
0 4000
3000 5000
5001 8000
7000 10000
樣例輸出
0.5
樣例說明
  第2個區間往右移0.5;第3個區間往左移0.5即可。
數據規模和約定
  對於30%的評測用例,1 ≤  n ≤ 10;
  對於100%的評測用例,1 ≤  n ≤ 10000,0 ≤  ai <  bi  ≤ 10000。
 
區間移位,最小是移動0.5,這個可以很容易想到,因為給出的區間端點都是整數,要使得移位最小,顯然是要平分的比如兩個區間之間空了1,彼此相對移動0.5,就可以填補。
所以首先所有的數據都乘以2,最后的結果再除以2即可。
要確定移動區間的大小,可以用二分來一點一點的逼近最小的移動標准,給定一個標准,判斷是否可行。需要先對所有的區間進行排序,這里對區間的右端點升序排序,為啥不按左端點排序,如果按照左端點排序,可能產生錯誤答案,比如樣例
3
0 1000
100 900
1100 10000
顯然把第二個區間左移100,第一個右移100即可,如果是按照左端點升序排序,也就是給定的順序,需要移動200才能滿足,這是不對的,所以按右端點排序,但是右端點排序后可能出現誤判,因為我們每到一個區間,就要判斷這個區間的左端點與前面已經合並的區間最右點的關系,比如說左邊已經合並的區間的右端點是100,然后我們按照右端點排序的兩個區間有1000 2000和100 2100,第一個區間不需要移動的,也就是說如果給出的移動標准低於1000,可能就會誤判成不可行,但是實際是可行的,所以for循環里加了個while循環尋找后面的左端點考前的區間,然后標記使用過,下次不再使用。
代碼:
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
typedef long long ll;
typedef pair<int,int> pa;
pa l[10001];
int n;
bool cmp(pa a,pa b) {
    if(a.second == b.second)return a.first < b.first;
    return a.second < b.second;
}
bool check(int d) {
    bool vis[100001] = {false};
    int last = 0,j = 0;///已經合並區間的最右端點
    for(int i = 0;i < n && last < 20000;i += (j == i),j = i) {
        while(j < n && (vis[j] || l[j].first - last > d)) j ++;///找到滿足當前標准的左端點靠前的區間
        if(j >= n) return false;
        vis[j] = true;
        if(last - l[j].first >= d) last = max(last,l[j].second + d);///重疊部分比d大,最多往右移動d
        else {///新區間接在了last后面
            last += l[j].second - l[j].first;
        }
    }
    return last >= 20000;
}
int main() {
    scanf("%d",&n);
    for(int i = 0;i < n;i ++) {
        scanf("%d%d",&l[i].first,&l[i].second);
        l[i].first *= 2;
        l[i].second *= 2;
    }
    sort(l,l + n,cmp);
    int l = 0,r = 20000;
    while(l < r) {//二分尋找最合適標准
        int mid = (l + r) / 2;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    if(l % 2) printf("%.1f",l / 2.0);
    else printf("%d",l / 2);
    return 0;
}

 


免責聲明!

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



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