算法 {区间最大覆盖(让一个固定长度区间来覆盖若干区间)}

算法 {区间最大覆盖(让一个固定长度区间来覆盖若干区间)}

区间最大覆盖(让一个固定长度区间来覆盖若干区间)

定義

一維坐標系上 有若干個不相交(端點可以重合)的區間A, 比如按照左端點排序後為[l1,r1], [l2,r2], ... 滿足r1<=l2, 選擇一個長度為Len的區間 使得他與A的交集的長度最大;
. 比如A= [ [0,1], [2,4], [8,9]]; Len=4, 選擇答案區間為[0,4] 交集長度為3;
假如區間集合A 他裡面的區間是相交的, 那麼你可以先進行一遍區間合併(即把[0,4] [2,5]合併為[0,5]);

算法

模板

令答案區間為[L,R], 可以證明 他一定可以形如: R=riL=li的性質, 因此使用雙指針算法;
下面的代碼有2個 (一個是計算R=ri)(另一個是計算L=li), 求出的結果是一樣的;

代碼
{ // ___Intervals_MaximumCoverage (枚舉答案區間的右端點)
    using __PointType_ = ?;
    const pair<__PointType_,__PointType_> * __Itvs = ?.data();
    ASSERT_MSG_( "__Itvs是按照*左端點*排序的,且不會相交(比如`[[1,2] [2,3] [4,5]]`是合法的)");
    using __AnsType_ = conditional_t< is_integral<__PointType_>::value, long long, Double>;
    const int __N = ?;
    const __AnsType_ __MaxLen = ?;
    int __lefInd = 0;
    __AnsType_ __ANS = 0;
    for( int i = 0; i < __N; ++i){
        __AnsType_ lefPos = __Itvs[ i].second - __MaxLen;
        while( __lefInd < i  &&  lefPos >= __Itvs[ __lefInd].second){
            __ANS -= (__Itvs[ __lefInd].second - max<ANS_TYPE_>( __Itvs[i-1].second - __MaxLen, __Itvs[ __lefInd].first));
            ++ __lefInd;
        }
        if( __lefInd != i){
            __ANS -= (__Itvs[ __lefInd].second - max<ANS_TYPE_>( __Itvs[i-1].second - __MaxLen, __Itvs[ __lefInd].first));
            __ANS += (__Itvs[ __lefInd].second - max<ANS_TYPE_>( lefPos, __Itvs[ __lefInd].first));
            __ANS += (__Itvs[ i].second - __Itvs[ i].first);
        }
        else{
            __ANS = (__Itvs[ i].second - max<ANS_TYPE_>( lefPos, __Itvs[ i].first));
        }
        //>< 如果答案區間為`[lefPos, Itvs[i].second]` 此時他的覆蓋長度為`__ANS`;
        
    }
} // ___Intervals_MaximumCoverage (枚舉答案區間的右端點)

{ // ___Intervals_MaximumCoverage (枚舉答案區間的左端點)
    using __PointType_ = ?;
    const pair<__PointType_,__PointType_> * __Itvs = ?.data();
    ASSERT_MSG_( "__Itvs是按照*左端點*排序的,且不會相交(比如`[[1,2] [2,3] [4,5]]`是合法的)");
    using __AnsType_ = conditional_t< is_integral<__PointType_>::value, long long, Double>;
    const int __N = ?;
    const __AnsType_ __MaxLen = ?;
    int __rigInd = __N-1;
    __AnsType_ __ANS = 0;
    for( int i = __N-1; i >= 0; --i){
        ANS_TYPE_ rigPos = __Itvs[ i].first + __MaxLen;
        while( __rigInd > i  &&  rigPos <= __Itvs[ __rigInd].first){
            __ANS -= (min<ANS_TYPE_>( __Itvs[i+1].first + __MaxLen, __Itvs[ __rigInd].second) - __Itvs[ __rigInd].first);
            -- __rigInd;
        }
        if( __rigInd != i){
            __ANS -= (min<ANS_TYPE_>( __Itvs[i+1].first + __MaxLen,__Itvs[ __rigInd].second) - __Itvs[ __rigInd].first);
            __ANS += (min<ANS_TYPE_>( rigPos, __Itvs[ __rigInd].second) - __Itvs[ __rigInd].first);
            __ANS += (__Itvs[ i].second - __Itvs[ i].first);
        }
        else{
            __ANS = (min<ANS_TYPE_>( rigPos, __Itvs[ i].second) - __Itvs[ i].first);
        }
        //>< 如果答案區間為`[Itvs[i].first, rigPos]` 此時他的覆蓋長度為`__ANS`;
    }
} // ___Intervals_MaximumCoverage (枚舉答案區間的左端點)

2個答案區間

用兩個長度為Len的區間去覆蓋 求最大覆蓋長度;

此時答案分為2種情況:
1(這2個答案區間是連續的): 即[L, L+Len] [L+Len, L+2*Len], 此時就轉換為一個2*Len區間覆蓋問題;
2(不是連續的): 即[Li, Li+Len] [Lj, Lj+Len] 此時令Lef[i] = max(R1,R2,...,Ri)其中Ri表示(選擇一個長度為Len且右端點與ri重合的最大覆蓋長度), 同理Rig[i] = max(Li,L[i+1],...,LN) Li表示(左端點為li的長度為Len的答案區間的最大覆蓋), 然後枚舉max( Lef[i] + Rig[i+1])為答案;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值