题意:输入h,k,h是邮票需要的数量, k是面额不同的邮票的种数,要求输出,如果k种邮票任意组合成h张所能取得的一系列和,是从1开始连续且长度最长的,就将这种情况输出出来,并且邮票的和能达到的最大连续值也输出出来。
题解:用两个数组den[N],表示当前有哪些不同面面额的邮票,den[0]一定是1,不然无法从1连续,另一个数组是val[N],表示当前这种面额的邮票所能达到的最大连续面额,
因此val[0] 是h*1,然后进行递归来更新每种面额val值,然后每种面额的邮票的选取也是有范围的,假设当前要找cur这个位置的面额,是从den[cur - 1] + 1 到 val[cur - 1] + 1,如果超过了这个范围就会导致无论怎么取值都不会连续,然后接着用递归从这个范围内找到每个面额和最大连续值。
#include <stdio.h>
#include <string.h>
const int N = 10;
const int MAX = 200;
int h, k, den[N], pos[MAX], val[N], ans, res[N];
void dfs(int num, int now, int count) {
if (num >= h) {
pos[count] = 1;
return;
}
pos[count] = 1;
for (int i = 0; i <= now; i++)
dfs(num + 1, now, count + den[i]);
}
void solve(int cur) {
if (cur >= k) {
if (val[cur - 1] > ans) {
ans = val[cur - 1];
memcpy(res, den, sizeof(den));
}
return;
}
for (int i = den[cur - 1] + 1; i <= val[cur - 1] + 1; i++) {
memset(pos, 0, sizeof(pos));
den[cur] = i;
dfs(0, cur, 0);
int num = 0, n = 1;
while (pos[n++])
num++;
val[cur] = num;
solve(cur + 1);
}
}
int main() {
int i, j;
while (scanf("%d%d", &h, &k) && (h || k)) {
ans = 0;
den[0] = 1;
val[0] = h;
solve(1);
for (int i = 0; i < k; i++)
printf("%3d", res[i]);
printf(" ->%3d\n", ans);
}
return 0;
}