某國家發行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...