郵票面值設計(codevs 1047) 題解

【問題描述】

給定一個信封,最多隻允許粘貼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.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章