給定一個信封,最多隻允許粘貼N張郵票,計算在給定K(N+K≤40)種郵票的情況下(假定所有的郵票數量都足夠),如何設計郵票的面值,能得到最大值MAX,使在1~MAX之間的每一個郵資值都能得到。例如,N=3,K=2,如果面值分別爲1分、4分,則在1分~6分之間的每一個郵資值都能得到(當然還有8分、9分和12分);如果面值分別爲1分、3分,則在1分~7分之間的每一個郵資值都能得到。可以驗證當N=3,K=2時,7分就是可以得到的連續的郵資最大值,所以MAX=7,面值分別爲1分、3分。
【樣例輸入】
3 2
【樣例輸出】
1 3
MAX=7
【解題思路】
本題爲NOIP1999第三題,初看感覺挺簡單的(不就一個搜索嗎,一個一個往上搜就行了啊),但寫着寫着,就發現出了點問題……
下面說一說正解。
首先,我們設定一個數組,用來存放對於某一個值x它所需要的最少郵票數是多少,當某個值所需要的郵票數大於K的時候,就可以不要再往下了(因爲再往下就不是連續的了)。
這樣一來就好辦了,每一次找出來連續的郵票數最多的時候,就更新最優解。詳見代碼。
【代碼實現】
1 var a,b,f:array[-1..40] of longint;//f記錄用x種郵票所取得的連續的郵票面值的最大值是多少,b是目前來說的最優解,a是最終結果 2 v:array[0..10000] of longint;//記錄x至少需要多少張郵票 3 i,j,n,k:longint; 4 procedure dfs(x,y:longint);//y是當前能取的最大值,x是當前取第幾張 5 var i,j,z,m:longint; 6 ss:array[0..10000] of longint;//方便回溯 7 begin 8 if y<b[x-1] then 9 exit;//如果y比在沒有這次搜索前的最大值還小,就不需要搜索,肯定不是最優解 10 if x>k then 11 exit;//已取完k張 12 ss:=v; 13 for i:=b[x-1]+1 to y+1 do 14 begin 15 b[x]:=i;//第x張取i 16 m:=y; 17 j:=0; 18 while v[j]<=n do 19 begin 20 for z:=1 to x do 21 if v[j+b[z]]>v[j]+1 then 22 v[j+b[z]]:=v[j]+1;//更新面額所需的最少郵票數 23 inc(j); 24 end; 25 while v[m+1]<=n do 26 inc(m);//連續能取到的郵票的最大面值 27 if (m>f[x])and(x=k) then//如果全部取完了,更新最優值 28 a:=b; 29 if m>f[x] then//更新取x種郵票的最優值 30 f[x]:=m; 31 dfs(x+1,m); 32 v:=ss; 33 end; 34 end; 35 begin 36 readln(n,k); 37 for i:=1 to 10000 do 38 v[i]:=maxlongint;//初始化 39 dfs(1,0); 40 for i:=1 to k do 41 write(a[i],' '); 42 writeln; 43 writeln('MAX=',f[k]); 44 end.