【Tai_mount】 演算法學習 - 線性動態規劃 - luoguP1280 尼克的任務
想了一個下午加半個早上,但做出來感覺十分舒爽!
本篇題解作者腦抽把分鐘都寫成天了,沒啥大問題,就不改了。
時間複雜度:O(N+K)
dp[i]表示:若該天空閒(可以接新任務),該天之前的最大空閒時間。若該天不可能空閒,則為-1
dp[i]初值均為-1(i>1),dp[1]初值為0:第一天必然空閒。(以下說的所有“空閒”都是指該天能接新任務)
設task[i][j]為:以第i天作為開始時間的第j個任務。我的程式裡用陣列模擬連結串列儲存,剩下來很多空間。(所以我的程式碼裡沒有這個陣列,這裡為了方便表示才寫的)。同時,len[i]表示第i天有len[i]個任務開始。
我們模擬的都是該天空閒的情況,若任何情況下該天都不可能空閒,dp[i]就是-1,這個點後面還會講到。
- 若第i天空閒:
- 若第i天有新任務可以接:遍歷各任務,任務j:dp[i+t[j]]=max(dp[i+t[j]],dp[i])
- 若第i天沒有新任務可以接:dp[i+1]=max(dp[i]+1,dp[i+1])
所求:dp[n+1]
思路說明
(真的遇到過很多問題啊)
首先我們第一個想到的就是拿子問題設dp陣列。每一個狀態由兩個量覺得:空閒/不空閒,第幾天。值設為子問題答案。
所以設dp[i][j]為第i天前的最大空閒天數,j=0則當天空閒,j=1則當天不空閒。
這裡為什麼要設是第i天前
我們發現:
- 若第i天j=0:
- 若無任務可以接:dp[i+1][0]=max(dp[i][0]+1,dp[i+1][0])。也就是第i天摸魚了,空閒時間+1
- 若有任務可以接,接了任務j,任務的持續時間為t[j]:dp[i+t[j]]=max(dp[i+t[j]],dp[i])。
- 若第i天j=1:他能做什麼呢?他什麼也做不了,沒法接任務的狀態更新不了任何東西
審視完以後,我們發現不空閒的狀態不能接任務,也並非最終答案(最終答案應該是dp[n+1][0]),所以,我要他有何用?
我們簡化dp陣列為:第i天空閒狀況下,第i天前的最長休息時間。
然後作者就這樣寫了,一直沒過,我們漏掉一個很重要的東西:第i天一定是在空閒狀況下。
如果這一天根本就不可能空閒下來,比如第一天有兩個任務,13,14,那麼2,3兩天一定空不下來。
我們還神奇的發現,如果第i天空閒,接了一個長度為t的任務,任務持續於i~i+t-1天的。也就是說i+t這一天一定空閒。同樣的,第i天空閒又沒有任務可接,i+1天也同樣是空閒的。
抽象出來,我們可以建一個perm的bool陣列,僅當perm為true的時候才可以由此狀態更新後面的狀態,perm為false就直接跳過。而某狀態可以把它所更新的狀態的perm都設成true。
事實上後來還能簡化掉perm,因為設perm和更新dp都是去操作同一個狀態,如果第i天沒接任務就都是設i+1,接了任務就是設i+t。那我們直接刪掉perm,把dp陣列初值都賦成-1,然後dp[1]單獨賦成0。第一天肯定是能接任務的。
程式碼實現:
#include<iostream>
#include<cstring>
using namespace std;
const int N=10007;
int n,k;
int edges[N],fst[N],nxt[N],dp[N];
void input(){//用連結串列儲存任務,接在任務的開始時間處。edges[N]裡儲存持續時間,因為作者是學儲存圖的時候學的連結串列,所以習慣這樣寫
cin>>n>>k;
int p,t;
for(int i=1;i<=k;i++){
cin>>p>>t;
edges[i]=t;
if(!fst[p]){
fst[p]=i;
continue;
}
int f=fst[p];
while(nxt[f]){
f=nxt[f];
}
nxt[f]=i;
}
}
void dpfun(){
memset(dp,-1,sizeof(dp));
dp[1]=0;
for(int i=1;i<=n;i++){
if(dp[i]==-1) continue;
int f=fst[i];
if(!f){
dp[i+1]=max(dp[i]+1,dp[i+1]);
continue;
}
dp[i+edges[f]]=max(dp[i+edges[f]],dp[i]);
while(nxt[f]){
f=nxt[f];
dp[i+edges[f]]=max(dp[i+edges[f]],dp[i]);
}
}
}
void output(){
cout<<dp[n+1];
}
int main(){
input();
dpfun();
output();
return 0;
}
連結串列沒有學過可以補一下哦~這裡就不贅述了。
謝謝觀看。