1. 程式人生 > >HDU6249 K區間最大覆蓋 【dp】

HDU6249 K區間最大覆蓋 【dp】

連結

描述

給定包含1至n,n個點的點集, (1n2000)(1 \leq n \leq 2000 ) 再給定 m個區間 [a,b][a,b] (1abn)(1 \leq a \leq b \leq n ) 求取k個區間對應的點集,使得其並集最大

分析

先拆分這m個區間, [a,b][a,b] 拆分為 [a,b],[a+1,b],[a+2,b],...,[b2,b],[b1,b],[b,b][a,b],[a+1,b],[a+2,b],...,[b-2,b],[b-1,b],[b,b]

b2,b],[b1,b],[b,b] 不難看出拆分之後 m變多,k不變 最優選取也不變(最優選取選擇的k個在目前擴充後的m裡也有) 我們又發現了以下事實:當最優選取的k區間中包含[a,b]時,我們去掉[a,b],換成[a,b+1],最優選取依然有效。 所以能對最優選取做出貢獻的僅有 由某位置為起始點的區間中最長的一個區間。

dp[pos][rk]dp[pos][rk] , pos指前pos位,rk指最多使用rk個區間,向後繼狀態dp

\quad兩個普通轉移,表示沒有取新的區間時的情況: dp[pos+1][rk]=max(itself,dp[pos][rk])d

p[pos][rk+1]=max(itself,dp[pos][rk]) dp[pos+1][rk] = max( itself ,dp[pos][rk] )\\ dp[pos][rk+1] = max( itself ,dp[pos][rk] ) \quad一個特殊轉移,表示取了可取的最長區間的情況: dp[pos+len][rk+1]=max(itself,dp[pos][rk]+len) dp[pos+len][rk+1] = max( itself , dp[pos][rk] + len )
\quad其中len表示pos位置之後,單子區間之內,最長的可取區間長 \quad核心在於上面的程式碼可能把某區間分成多份取,如果沒有必要,那麼max會幫我們選擇不分開的那種,如果有必要(也就是兩個區間重疊,我們取a區間的全部和b區間的後半部分,多個區間同理),那麼我們就選收益最大的。

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;

int dp[2010][2010];
int mxlen[2010];

int sove(){
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);

    while(m--){
        int s,e;
        scanf("%d%d",&s,&e);
        mxlen[s-1] = max(mxlen[s-1],e-s+1);
    }//每個區間所做的最大貢獻,就是將區間前方的點(s-1) 的 單區間可延續長度(len) 增加到了區間長度

    for(int i=1;i<n;i++){
        mxlen[i] = max(mxlen[i],mxlen[i-1]-1);
    }//區間的拆分,保留後半部分加入影響

    for(int pos = 0;pos < n;pos++ ){
        int adv = mxlen[pos];//當前位置,只用一個區間(或區間的一部分),所能延長的最遠長度
        for(int rd = 0;rd <= k; rd++ ){
            dp[pos+1][rd] = max(dp[pos+1][rd],dp[pos][rd]);
            dp[pos][rd+1] = max(dp[pos][rd+1],dp[pos][rd]);
            dp[pos+adv][rd+1] = max(dp[pos+adv][rd+1],dp[pos][rd]+adv);
        }
    }

    return dp[n][k];
}

int main(void){

    int _T;
    scanf("%d",&_T);

    for(int T=1;T<=_T;T++){

        memset(dp,0,sizeof(dp));
        memset(mxlen,0,sizeof(mxlen));

        printf("Case #%d: %d\n",T,sove());

    }

    return 0;
}

才疏學淺,如有錯誤,歡迎指正。