8 3 尼克的任務

2021-06-01 14:05:31 字數 3385 閱讀 7873

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的話就可以了。因為這樣的話,你後面的過程相當於是已知的。我們只要在記錄一下以這個點為開始的工作有多少,...