HDU6249 K區間最大覆蓋 【dp】
阿新 • • 發佈:2018-12-14
連結
描述
給定包含1至n,n個點的點集, 再給定 m個區間 求取k個區間對應的點集,使得其並集最大
分析
先拆分這m個區間, 拆分為 不難看出拆分之後 m變多,k不變 最優選取也不變(最優選取選擇的k個在目前擴充後的m裡也有) 我們又發現了以下事實:當最優選取的k區間中包含[a,b]時,我們去掉[a,b],換成[a,b+1],最優選取依然有效。 所以能對最優選取做出貢獻的僅有 由某位置為起始點的區間中最長的一個區間。
取 , pos指前pos位,rk指最多使用rk個區間,向後繼狀態dp
兩個普通轉移,表示沒有取新的區間時的情況: 一個特殊轉移,表示取了可取的最長區間的情況: 其中len表示pos位置之後,單子區間之內,最長的可取區間長 核心在於上面的程式碼可能把某區間分成多份取,如果沒有必要,那麼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;
}
才疏學淺,如有錯誤,歡迎指正。