UVa 165 - Stamps 解题报告(暴力)

来源:互联网 发布:上海银行 淘宝金卡 编辑:程序博客网 时间:2024/05/29 03:47

 Stamps 

The government of Nova Mareterrania requires that various legal documents have stamps attached to them so that the government can derive revenue from them. In terms of recent legislation, each class of document is limited in the number of stamps that may be attached to it. The government wishes to know how many different stamps, and of what values, they need to print to allow the widest choice of values to be made up under these conditions. Stamps are always valued in units of $1.

This has been analysed by government mathematicians who have derived a formula for n(h,k), where h is the number of stamps that may be attached to a document, k is the number of denominations of stamps available, and n is the largest attainable value in a continuous sequence starting from $1. For instance, if h=3, k=2 and the denominations are $1 and $4, we can make all the values from $1 to $6 (as well as $8, $9 and $12). However with the same values of h and k, but using $1 and $3 stamps we can make all the values from $1 to $7 (as well as $9). This is maximal, so n(3,2) = 7.

Unfortunately the formula relating n(h,k) to hk and the values of the stamps has been lost--it was published in one of the government reports but no-one can remember which one, and of the three researchers who started to search for the formula, two died of boredom and the third took a job as a lighthouse keeper because it provided more social stimulation.

The task has now been passed on to you. You doubt the existence of a formula in the first place so you decide to write a program that, for given values of h and k, will determine an optimum set of stamps and the value of n(h,k).

Input

Input will consist of several lines, each containing a value for h and k. The file will be terminated by two zeroes (0 0). For technical reasons the sum of h and k is limited to 9. (The President lost his little finger in a shooting accident and cannot count past 9).

Output

Output will consist of a line for each value of h and k consisting of the k stamp values in ascending order right justified in fields 3 characters wide, followed by a space and an arrow (->) and the value of n(h,k) right justified in a field 3 characters wide.

Sample input

3 20 0

Sample output

  1  3 ->  7
    解题报告:经典题。打表过的……如下
string answer[] ={"  1 ->  1","  1  2 ->  2","  1  2  3 ->  3","  1  2  3  4 ->  4","  1  2  3  4  5 ->  5","  1  2  3  4  5  6 ->  6","  1  2  3  4  5  6  7 ->  7","  1  2  3  4  5  6  7  8 ->  8","  1 ->  2","  1  2 ->  4","  1  3  4 ->  8","  1  3  5  6 -> 12","  1  3  5  7  8 -> 16","  1  2  5  8  9 10 -> 20","  1  2  5  8 11 12 13 -> 26","  1 ->  3","  1  3 ->  7","  1  4  5 -> 15","  1  4  7  8 -> 24","  1  4  6 14 15 -> 36","  1  3  7  9 19 24 -> 52","  1 ->  4","  1  3 -> 10","  1  5  8 -> 26","  1  3 11 18 -> 44","  1  3 11 15 32 -> 70","  1 ->  5","  1  4 -> 14","  1  6  7 -> 35","  1  4 12 21 -> 71","  1 ->  6","  1  4 -> 18","  1  7 12 -> 52","  1 ->  7","  1  5 -> 23","  1 ->  8",};

百度了一下其他方法,这篇博客说的不错。http://blog.csdn.net/shuangde800/article/details/7755452
    参照上面的博客优化了一下之前的方法。每次枚举新的邮票时,邮票大小可以设定为当前最大邮票+1,到当前所有邮票有h张时可以组成的最大连续值+1。这样不会出现不连续,并且减少了盲目枚举,速度快了很多。换句话说,枚举的思路很好。代码如下:
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>#include <map>#include <set>#include <string>#include <iomanip>using namespace std;#define ff(i, n) for(int i=0;i<(n);i++)#define fff(i, n, m) for(int i=(n);i<=(m);i++)#define dff(i, n, m) for(int i=(n);i>=(m);i--)#define bit(n) (1LL<<(n))typedef long long LL;typedef unsigned long long ULL;void work();int main(){#ifdef ACM//    freopen("in.txt", "r", stdin);#endif // ACM    work();}/***************************************************/int ans;int res[11];int n, k;int stamp[11];int up;int id;int vis[222];void dfs1(int sta, int has, int sum){    vis[sum] = id;    if(has == n) return;    fff(i, sta, up)        dfs1(i, has+1, sum + stamp[i]);}void dfs2(int sta, int has){    ++id;    up = has-1;    dfs1(0, 0, 0);    int t = 0;    while(vis[t+1] == id) t++;    if(has == k)    {        if(ans < t)        {            ans = t;            memcpy(res, stamp, sizeof(stamp));        }        return;    }    fff(i, sta, t+1)    {        stamp[has] = i;        dfs2(sta+1, has+1);    }}void work(){    while(scanf("%d%d", &n, &k) == 2 && (n||k))    {        ans = 0;        stamp[0] = 1;        dfs2(2, 1);        ff(i, k) printf("%3d", res[i]);        printf(" ->%3d\n", ans);    }}
    另外一种方法就是每次枚举组成1到val值所需要的最少邮票数,使用动态规划优化统计部分。效率上会好很多。代码如下:
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>#include <map>#include <set>#include <string>#include <iomanip>using namespace std;#define ff(i, n) for(int i=0;i<(n);i++)#define fff(i, n, m) for(int i=(n);i<=(m);i++)#define dff(i, n, m) for(int i=(n);i>=(m);i--)#define bit(n) (1LL<<(n))typedef long long LL;typedef unsigned long long ULL;void work();int main(){#ifdef ACM//    freopen("in.txt", "r", stdin);#endif // ACM    work();}/***************************************************/int ans;int res[11];int n, k;int stamp[11];int y[222];void dfs2(int sta, int has, int curMax){    if(has == k)    {        if(ans < curMax)        {            ans = curMax;            ff(i, k) res[i] = stamp[i];        }        return;    }    int tmp[222];    memcpy(tmp, y, sizeof(y));    fff(i, sta+1, curMax+1)    {        ff(j, sta*n) if(y[j]<n)            fff(num, 1, n-y[j])                y[j+i*num] = min(y[j+i*num], y[j]+num);        int t = curMax;        while(y[++t] <= n);        stamp[has] = i;        dfs2(i, has+1, t-1);        memcpy(y, tmp, sizeof(tmp));    }}void work(){    while(scanf("%d%d", &n, &k) == 2 && (n||k))    {        ans = 0;        stamp[0] = 1;        fff(i, 0, n) y[i] = i;        fff(i, n+1, 200) y[i] = 20;        dfs2(1, 1, n);        ff(i, k) printf("%3d", res[i]);        printf(" ->%3d\n", ans);    }}


0 0
原创粉丝点击