stamp 邮票设计 搜索02

来源:互联网 发布:面板数据 编辑:程序博客网 时间:2024/05/01 05:18

这道题目和普通的邮票设计不一样,我们可以展示一下题目!

邮票【问题描述】邮局发行一套票面有 n(0<n<=10)种不同面值的邮票。若限每封信所贴的邮票张数不得超过 m 枚,存在整数 r 使得用不超过 m(0<m<=2n)枚的邮票,可以贴出连续整数 123,…,r 值来,找出这种面值数,使得 r 值最大。【输入】一行,输入 N 及 M【输出】输出 R【样例】stamp. in2 3stamp. out7

放思路:

3、 邮票解题思路:DFS+回溯法。邮票问题搜索的状态应该是已经确定的邮票面值(各不相同并且总数不超过n)和它们能够贴出的最大连续邮资区间,以此来枚举下一个可能的邮票面值。因此,很自然地,使用原题中的标识符,数组 x 记录当前已经确定的邮票面值,整数 r 表示当前使用不超过 m 张邮票能贴出的最大连续邮资区间。对于第 i 层的结点,x[1…i]表示当前已经有 i 个面值确定,r 表示由 x[1…i]能贴出的最大连续区间。现在,要想把第 i 层的结点往下扩展,有两个问题需要解决:① ,哪些数有可能成为下一个的邮票面值,即 x[i+1]的取值范围是什么; ② ,对于一个确定的 x[i+1],如何更新 r 的值让它表示 x[1…i+1]能表示的最大连续邮资区间。~第一个问题很简单,x[i+1]的取值要和前 i 个数各不相同,最小应该是 x[i] + 1,最大就是 r+1,否则 r+1 没有办法表示。我们现在专注第二个问题。第二个问题自己有两种思路:一,计算出所有使用不超过 m 张 x[1…i+1]中的面值能够贴出的邮资,然后从 r+1 开始逐个检查是否被计算出来。二,从 r+1 开始,逐个询问它是不是可以用不超过 m 张 x[1…i+1]中的面值贴出来。第二种方法,由于前面 i 种邮票不能贴出 r+1,因此贴 r+1 必须要 i+1 种邮票进入,但是 i+1 种邮票需要多少张呢? 又替换哪一些呢 ? 这并不很好实现,我们换一个角度思考,还是按照方法 1 着手。第二个问题第一种思路:定义数组 y[postage]表示用当前的面值 postage 贴出某个邮资所需要的最少的邮票数(初始时都是无穷大); S(i)表示 x[1…i]中不超过 m 张邮票的贴法的集合,S(i)中元素的值就是它所表示的贴法贴出来的邮资,于是,可以把 S(i)中的元素按照它们的值的相等关系分成 k 类。第 j 类表示贴出邮资为 j 的所有的贴法集合,用 T(j)表示,T(j)有可能是空集,例如对于{1,2,4},T(7)为空集,T(8)={{4,4}}。此时有:S(i) = T(1) U T(2) U T(3) U … U T(k),U 表示两个集合的并。现在考虑 x[i+1]加入后对当前状态 S(i)的影响。假设 s 是 S(i)中的一个元素,即 s 表示一种合法的贴法,x[i+1]对s 能贴出的邮资的影响就是x[i+1]的多次重复增加了s 能贴出的邮资。这样说是因为有两种情况不需要考虑:一,从 s 中去掉几张邮票,把 x[i+1]加进去,这没有意义,因为从 s 中去掉几张邮票后 s 就变成了 S(i)中的另一个元素 t,我们迟早会对 t 考虑 x[i+1]的影响。二,将 x[i+1]加入 s,同时再把 x[1]也加入 s(如果 s 中还能再贴两张邮票的话),这也没有意义,原因同一。所以,x[i+1]对s 的影响就是,如果s 中贴的邮票不满m 张,那就一直贴x[i+1],直到 s 中有 m 张邮票,这个过程会产生出很多不同的邮资,它们都应该被加入到 S(i+1)中。因为 s 属于 S(i),它也必定在某个 T(k)中,而 T(k)中能产生出最多不同邮资的是 T(k)中用的邮票最少的那个元素。至此,原题中的解法就完全出来了:用数组 x 记录当前已经确定的邮票面值,用 r 表示当前最大的连续邮资区间,用数组 y 表示用当前的面值贴出某个邮资所需要的最少的邮票数。前 i 种面值的邮票,最大贴出邮资 [ 0, x[i]*m ] 。增加一种新面值 x[i+1] 的邮票,在前(i)种邮票面值最大可能取到的邮资区间范围内进行, y[ ]数组更新操作,如果前i 种邮票贴出面值为postage 的最少邮票张数 num<m,则剩下最多 m-num 张邮票,就一次去贴 k 张 x[i+1]邮票(1<=k<=m-num),更新贴出面值为 postage+k*x[i+1]面值的邮资最少需要邮票的张数 y[postage]+k。最后,在前面的各种面值邮资最少需要贴出的邮票张数数组更新完成后,查找贴面值为 x[i+1]的邮票最大的邮资连续区间能贴到多少?然后更新 r,继续 DFS 查找下一种邮票的面值,直到 n 种邮票的面值都查找完成。回溯:当然,前 i 种邮票面值确定,当前步骤选择第 i+1 种邮票的面值可能不止 x[i+1] 这一种,那么对于 i+1 种邮票面值取其他值最大连续邮资区间的搜索,需要回溯恢复当前搜索步骤原始的最大区间 r 的值和 y[ ]数组的值。

最后实现的代码::

#include<stdio.h>#include<stdlib.h>#include<algorithm>using namespace std;int x[10];int n,m,r;int y[100001];int ls[1001];int calc(int new_i){    int i;    int max=0;    for(i=1;i<=1000;i++)ls[i]=0;    int len=0;    for(i=1;i<=r;i++){        if(y[i]<m){            int ts_y=y[i];            int ts_i=i;            while(ts_y<n){                ts_i+=x[new_i];                ts_y++;            }            ls[++len]=ts_i;        }        int max_n=0;        sort(ls+1,ls+len+1);        for(int k=2;k<=len;k++)            if(ls[k]-1!=ls[k-1])max_n=k-1;        if(max_n>max)max=max_n;    }    return max;}void search(int i,int r){    int j;    for(j=x[i-1]+1;j<=r+1;j++){        x[i]=j;        int max_r=calc(i);        if(max_r>r)r=max_r;        if(i<n)search(i+1,r);        else{            printf("%d\n",r);            exit(0);        }    }}int main(){    freopen("stamp.in","r",stdin);    freopen("stamp.out","w",stdout);    int i,j,k,n,m;    scanf("%d%d",&n,&m);    for(i=1;i<=m;i++)y[i]=i;    x[1]=1;    search(2,m);    return 0;}

—————啊!怎么办,完了,这个还是没有过的!!!555,明天再发标程,一抹一样的标题,好吧,必须有点改动,555


—————————————————————————————————————————————————————

0 0
原创粉丝点击