UVa 165 - Stamps(连续邮资问题)

来源:互联网 发布:officeim网络办公 编辑:程序博客网 时间:2024/06/07 03:36

题意:

某国家发行k种不同面值的邮票,并且规定每张信封上最多只能贴h张邮票。 公式n(h,k)表示用从k中面值的邮票中选择h张邮票,可以组成面额为连续的1,2,3,……n, n是能达到的最大面值之和。
例如当h=3,k=2时, 假设两种面值取值为1,4, 那么它们能组成连续的1……6, 虽然也可以组成8,9,12,但是它们是不连续的了。

解析:

    首先开一个数组stampVal[1...i]来保存各个面值,再开一个maxVal[1...i]来保存当前所有面值能组成的最大连续面值。
    那么,我们可以确定stampVal[1] 一定是等于1的。因为如果没有1的话,很多数字都不能凑成。
    然后相应的,maxVal[1]=1h
    h为允许贴邮票的数量

接下去就是确定第二个,第三个……第k个邮票的面值了,这个该怎么确定呢?
    对于stampVal[i+1],它的取值范围是stampVal[i]+1 maxVal[i]+1
stampVal[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) {    if(pos >= h) {        vis[sum] = true;        return;    }    vis[sum] = true;    for(int i = 1; i <= num; i++)        check(pos+1, sum+stampVal[i], num);}

vis是一个全局数组, 调用递归时先初始化为0。然后用它来记录出现过的面值之和。
最后只需要从vis数组的下标1开始枚举,直到不是true值时就是能达到的最大连续面值。

AC代码

#include <cstdio>#include <cstring>#include <algorithm>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) {    if(pos >= h) {        vis[sum] = true;        return;    }    vis[sum] = true;    for(int i = 1; i <= num; i++)        check(pos+1, sum+stampVal[i], num);}void dfs(int curKind) {    if(curKind >= K) {        if(maxVal[curKind] > maxAns) {            maxAns = maxVal[curKind];            memcpy(ans, stampVal, sizeof(stampVal));        }        return;    }    for(int i = stampVal[curKind]+1; i <= maxVal[curKind]+1; i++) {        memset(vis, false, sizeof(vis));        stampVal[curKind+1] = i;        check(0, 0, curKind+1);        int cnt = 0;        while(vis[cnt]) {cnt++;}        maxVal[curKind+1] = cnt-1;        dfs(curKind+1);    }}int main() {    while(scanf("%d%d", &h, &K) != EOF && (h || K)) {        stampVal[1] = 1;        maxVal[1] = h;        maxAns = -INF;        dfs(1);        for(int i = 1; i <= K; i++) {            printf("%3d", ans[i]);        }        printf(" ->%3d\n", maxAns);    }    return 0;}

以上题解转自

http://blog.csdn.net/shuangde800 , By D_Double

0 0
原创粉丝点击