这个题题目大意就比较难理解。题意:给定 h(贴邮票位置数),k(允许使用的邮票面值数) (h+k<=9) 求n(h,k) (即用k种面值的邮票在最大h个位置拼成连续面值的最大值) 。
样例:h=3 k=2。若两种面值为1,3 则可以拼出 1,2,3,4,5 ,6 ,7 ,9 连续的最大和只到7。
因此输出:
1 3 -> 7
思路:数据量不大,可以一个一个数的往后推,首先,面值为1的邮票是必须选的,否则起码面值和“1”就凑不出来了。从1着手,其下一个数的取值范围必定在当前面值凑出数的(最小值+1)与(最大值+1)之间,比如:h为3,k为3,当前为1 3,则下一个数的范围为:4~8之间,下一个数的取值小了重复,而大了,则必定会出现断点,比如上例中如果下一个数是9,因为8必然凑不出来,所以9就是无效数据。以此回溯枚举所有位置面值的和,再判定连续的最大值便是所求的结果。
代码如下:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> using namespace std; int kval[11], save[11]; bool visit[190]; // 180时还RE,貌似最大面值和能达到180+ int h, k, _max; void check(int n, int cur, int sum) // 将当前所具有的面值 和的所有情况都枚举出来并利用visit数组进行标记 { if(cur == h) { visit[sum] = true; return ; } visit[sum] = true; for(int i=0; i <= n; i++) check(n, cur+1, sum+kval[i]); } void dfs(int cur, int num) // 依次往下推导下一个面值 { if(cur > k) { if(num-1 > _max) { _max = num-1; memcpy(save, kval, sizeof(kval)); } return ; } for(int i=kval[cur-1]+1; i<=num; i++) { kval[cur] = i; memset(visit, false, sizeof(visit)); check(cur, 0, 0); int j = kval[cur-1];//从上一层的面值和的数开始判断,直到遇到第一个false跳出 while(visit[++j]) ; dfs(cur+1, j); } } int main() { #ifdef test freopen("sample.txt", "r", stdin); #endif kval[0] = 0; kval[1] = 1; while(scanf("%d%d", &h, &k)) { if(!h && !k) break; _max = 0; dfs(2, h+1); for(int i=1; i<=k; i++) printf("%3d", save[i]); printf(" ->"); printf("%3d\n", _max); } return 0; }