UVa 165 Stamps(連續郵資問題)

2021-07-01 23:53:11 字數 2057 閱讀 4987

某國家發行k種不同面值的郵票,並且規定每張信封上最多只能貼h張郵票。 公式n(h,k)表示用從k中面值的郵票中選擇h張郵票,可以組成面額為連續的1,2,3,……n, n是能達到的最大面值之和。

例如當h=3,k=2時, 假設兩種面值取值為1,4, 那麼它們能組成連續的1……6, 雖然也可以組成8,9,12,但是它們是不連續的了。

首先開乙個陣列st

ampv

al[1...i]

來儲存各個面值,再開乙個ma

xval

[1...i]

來儲存當前所有面值能組成的最大連續面值。

那麼,我們可以確定st

ampv

al[1

] 一定是等於1的。因為如果沒有1的話,很多數字都不能湊成。

然後相應的,ma

xval

[1]=

1∗h

h為允許貼郵票的數量

接下去就是確定第二個,第三個……第k個郵票的面值了,這個該怎麼確定呢?

對於stampval[i+1],它的取值範圍是st

ampv

al[i

]+1m

axva

l[i]

+1sta

mpva

l[i]

+1好理解, 這一次取的面值肯定要比上一次的面值大, 而這次取的面值的上限是上次能達到的最大連續面值+1, 是因為如果比這個更大的話, 那麼就會出現斷層, 即無法組成上次最大面值+1這個數了。 舉個例子, 假設可以貼3張郵票,有3種面值,前面2種面值已經確定為1,2, 能達到的最大連續面值為6, 那麼接下去第3種面值的取值範圍為3~7。如果取得比7更大的話會怎樣呢? 動手算下就知道了,假設取8的話, 那麼面值為1,2,8,將無法組合出7 !

知道了這個以後,就可以知道回溯的大概思路了, 但是還不夠, 怎樣取得給定的幾個面值能夠達到的最大連續面值呢?

最直觀容易想到的就是直接遞迴回溯列舉所有情況, 便可知道最大連續值了。

這是查詢的函式

//pos表示當前的位置,sum表示面額的和,num表示當前的面額數

void check(int pos, int

sum, int num)

vis[sum] = true;

for(int i = 1; i <= num; i++)

check(pos+1, sum+stampval[i], num);

}

vis是乙個全域性陣列, 呼叫遞迴時先初始化為0。然後用它來記錄出現過的面值之和。

最後只需要從vis陣列的下標1開始列舉,直到不是true值時就是能達到的最大連續面值。

ac**

#include 

#include

#include

using

namespace

std;

const

int n = 200;

const

int inf = 0x3f3f3f3f;

bool vis[n];

int ans[n], stampval[n], maxval[n], maxans;

int h, k;

void check(int pos, int sum, int num)

vis[sum] = true;

for(int i = 1; i <= num; i++)

check(pos+1, sum+stampval[i], num);

}void dfs(int curkind)

return;

}for(int i = stampval[curkind]+1; i <= maxval[curkind]+1; i++)

maxval[curkind+1] = cnt-1;

dfs(curkind+1);

}}int main()

printf(" ->%3d\n", maxans);

}return

0;}

紫書刷題 UVA 712 S樹 S Trees

題目 我想用題目中給出的第二組輸入為例。3 x3 x1 x2 00010011 4000 010111 110000可以看做二進位制數000,可以轉化為十進位制的0,00010011中的第0位就是答案0 010可以看做二進位制數001,可以轉化為十進位制的1,00010011中的第1位就是答案0 1...