noip1999 邮票面值设计 (搜索+完全背包)

A1123. 邮票面值设计
时间限制: 1.0s   内存限制: 256.0MB  
总提交次数: 324   AC次数: 103   平均分: 49.85
将本题分享到:
       
   
试题来源
  NOIP1999 提高组
问题描述
  给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤13)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1~MAX之间的每一个邮资值都能得到。

  例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分);如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分、3分。
输入格式
  一行,两个数N、K
输出格式
  两行,第一行升序输出设计的邮票面值,第二行输出“MAX=xx”(不含引号),其中xx为所求的能得到的连续邮资最大值。
样例输入
3 2
样例输出
1 3
MAX=7


解析:

①搜索。对每一步,枚举邮票面值,然后搜索下一张邮票面值并更新最优解。

②完全背包确定搜索范围。

假设现在枚举到第 i 张邮票面值,第 i-1 张邮票面值为a[i-1],前 i-1 张邮票得到的最大连续值为x,则第 i 张邮票面值的范围就为 [a[i-1]+1,x+1];

假设现在有 n 张邮票,怎么得到其最大连续值呢?

用 f[i] 记录达到数值 i 所需的最小邮票数量,初始化为一个极大值。然后用完全背包算出 f[i] 的值,从 0 开始,第一个f[i]>n,则 i-1 就为最大连续值。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn1=40;
const int maxn2=10000;
int n,m,ans=0,f[maxn1][maxn2];
int a[maxn1+20],b[maxn2+20];

void dfs(int step,int s,int e)
{
  int i,j,k;
  if(step>m)
    {
      if(ans<e-1)for(ans=e-1,i=1;i<=m;i++)b[i]=a[i];
      return;
	}
  for(k=e;k>=s;k--)
    {
      j=a[step-1]*n;
      for(i=0;i<=j;i++)f[step][i]=f[step-1][i];
      memset(&f[step][j+1],25,sizeof(int)*((n*k+1-j)+10));
      
      for(j=n*k,i=k;i<=j;i++)
        f[step][i]=min(f[step][i],f[step][i-k]+1);
      for(i=e;i<=j+1;i++)if(f[step][i]>n)
        {
          a[step]=k,dfs(step+1,k+1,i);
          break;
		}
	}
}

int main()
{
  int i;
  memset(f[1],25,sizeof(f[1]));
  scanf("%d%d",&n,&m);
  for(i=0;i<=n;i++)f[1][i]=i;
  a[1]=1,dfs(2,2,n+1);
  for(i=1;i<m;i++)printf("%d ",b[i]);
  printf("%d\nMAX=%d\n",b[m],ans);
  return 0;
}



    • 1
      点赞
    • 1
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值