8.3 尼克的任務
源程式名 lignja.???(pas, c, cpp)
可執行檔名 lignja.exe
輸入檔名 lignja.in
輸出檔名 lignja.out
【問題描述】
尼克每天上班之前都連線上英特網,接收他的上司發來的郵件,這些郵件包含了尼克主管的部門當天要完成的全部任務,每個任務由乙個開始時刻與乙個持續時間構成。
尼克的乙個工作日為n分鐘,從第一分鐘開始到第n分鐘結束。當尼克到達單位後他就開始幹活。如果在同一時刻有多個任務需要完戍,尼克可以任選其中的乙個來做,而其餘的則由他的同事完成,反之如果只有乙個任務,則該任務必需由尼克去完成,假如某些任務開始時刻尼克正在工作,則這些任務也由尼克的同事完成。如果某任務於第p分鐘開始,持續時間為t分鐘,則該任務將在第p+t-1分鐘結束。
寫乙個程式計算尼克應該如何選取任務,才能獲得最大的空暇時間。
【輸入】
輸入資料第一行含兩個用空格隔開的整數n和k(1≤n≤10000,1≤k≤10000),n表示尼克的工作時間,單位為分鐘,k表示任務總數。
接下來共有k行,每一行有兩個用空格隔開的整數p和t,表示該任務從第p分鐘開始,持續時間為t分鐘,其中1≤p≤n,1≤p+t-1≤n。
【輸出】
輸出檔案僅一行,包含乙個整數,表示尼克可能獲得的最大空暇時間。
【樣例】
lignja.in lignja.out
15 6 4
1 21 6
4 11
8 58 1
11 5
【演算法分析】
題目給定的資料規模十分巨大:1≤k≤10000。採用窮舉方法顯然是不合適的。根據求最大的空暇時間這一解題要求,先將k個任務放在一邊,以分鐘為階段,設定minute[i]表示從第i分鐘開始到最後一分鐘所能獲得的最大空暇時間,決定該值的因素主要是從第i分鐘起到第n分鐘選取哪幾個任務,與i分鐘以前開始的任務無關。由後往前逐一遞推求各階段的minute值:
(1)初始值minute[n+1]=0
(2)對於minute[i],在任務表中若找不到從第i分鐘開始做的任務,則minute[i]比minute[i+1]多出一分鐘的空暇時間;若任務表中有乙個或多個從第i分鐘開始的任務,這時,如何選定其中的乙個任務去做,使所獲空暇時間最大,是求解的關鍵。下面我們舉例說明。
設任務表中第i分鐘開始的任務有下列3個:
任務k1 p1=i t1=5
任務k2 p2=i t2=8
任務k3 p3=i t3=7
而已經獲得的後面的minute值如下:
minute[i+5]=4,minute[i+8]=5,minute[i+7]=3
若選任務k1,則從第i分鐘到第i+1分鐘無空暇。這時從第i分鐘開始能獲得的空暇時間與第i+5分鐘開始獲得的空暇時間相同。因為從第i分鐘到i+5-1分鐘這時段中在做任務k1,無空暇。因此,minute[i]=minute[i+5]=4。
同樣,若做任務k2,這時的minute[i]=minute[i+8]=5
若做任務k3,這時的minute[i]=minute[1+7]=3
顯然選任務k2,所得的空暇時間最大。
因此,有下面的狀態轉移方程:
其中,tj表示從第i分鐘開始的任務所持續的時間。
下面是題目所給樣例的minute值的求解。
任務編號k12
3456
開始時間p11
48811
持續時間t26
11515
時刻i16
1514
1312
111098
7654
321minute[i]01
2340
1234
5612
34選任務號k00
0006
0040
0030
02注:選任務號為該時刻開始做的任務之一,0表示無該時刻開始的任務。
問題所求得最後結果為從第1分鐘開始到最後時刻所獲最大的空暇時間minute[1]。
主要演算法描述如下:
(1)資料結構
var p:array[1..10000]of integer;
t:array[1..10000]of integer;
minute:array[0..10001]of integer;
(2)資料讀入
① readln(n, k);
② 讀入k個任務資訊
for i:=1 to k do readln(p[i],t[i]);
(3)遞推求minute[i]
j:=k;
for i:=n downto 1 do
begin
minute[i]:=0;
if p[i]<>i then minute[i]:=1+minute[i+1]
else while p[j]=i do
begin
if minute[i+t[j]]>minute[i] then minute[i]:=minute[i+t[j]];
j:=j-1;
end;
end;
(4)輸出解
writeln(minute[1]);
var f,a,b:array[0..10000] of longint;
n,m,i,j,k,sum:longint;
begin
assign(input,'lignja.in'); assign(output,'lignja.out');
reset(input); rewrite(output);
readln(n,k);
for i:=1 to k do readln(a[i],b[i]);
j:=k; f[n+1]:=0;
for i:=n downto 1 do
begin
if a[j]<>i then f[i]:=f[i+1]+1;
while a[j]=i do
begin
if f[i+b[j]]>f[i] then
f[i]:=f[i+b[j]];
dec(j);
end;
end;
writeln(f[1]);
close(input); close(output);
end.
尼克的任務
題目描述 尼克每天上班之前都連線上英特網,接收他的上司發來的郵件,這些郵件包含了尼克主管的部門當天要完成的全部任務,每個任務由乙個開始時刻與乙個持續時間構成。尼克的乙個工作日為n分鐘,從第一分鐘開始到第n分鐘結束。當尼克到達單位後他就開始幹活。如果在同一時刻有多個任務需要完戍,尼克可以任選其中的乙個...
尼克的任務
傳送門 題目描述 尼克每天上班之前都連線上英特網,接收他的上司發來的郵件,這些郵件包含了尼克主管的部門當天要完成的全部任務,每個任務由乙個開始時刻與乙個持續時間構成。尼克的乙個工作日為n分鐘,從第一分鐘開始到第n分鐘結束。當尼克到達單位後他就開始幹活。如果在同一時刻有多個任務需要完戍,尼克可以任選其...
尼克的任務
傳送門 這道題雖然很基礎但是也不是很好想 我們一開始會想,用dp i 表示前i分鐘最大休息時間,之後你就完全不知道怎麼轉移了。阻礙你轉移的關鍵問題在於,你不知道後面會發生什麼,但是如果從後面倒著dp的話就可以了。因為這樣的話,你後面的過程相當於是已知的。我們只要在記錄一下以這個點為開始的工作有多少,...