zoukankan      html  css  js  c++  java
  • 邮票问题

    题目链接:https://www.luogu.org/problemnew/show/P2725

    http://www.joyoi.cn/problem/tyvj-1199

    http://tyvj.cn/p/1199

    题目限制

    时间限制 内存限制 评测方式 题目来源
    1000ms 131072KiB 标准比较器 Local

    题目描述

    给定一个信封,最多只允许粘贴N(N≤100)张邮票,我们现在有M(M≤100)种邮票,面值分别为:X1,X2……Xm(Xi≤255为正整数),并假设各种邮票都有足够多张。
    要求计算所能获得的邮资最大范围。即求最大值MAX,使1-MAX之间的每一个邮资都能得到。
    例如:N=4,有2种邮票,面值分别为1分,4分,于是可以得到1-10分和12分,13分,16分邮资,由于得不到11分和15分,所以邮资的最大范围max=10

    输入格式

    第一行为最多粘贴的邮票张数n。第二行为邮票种数m。以下m行各有一个数字表示邮票的面值。

    本地测试的输入格式:

    第一行:m,n的值,中间用一空格隔开。

    第二行:A[1..m](面额),每个数中间用一空格隔开。

    输出格式

    仅一个数,最大的max的值。

    算法分析:

    从面额1开始,建立递推关系方程。比如:面额1,2,4只用1张邮票行了,面额3可以表示为面额1,2的邮票和1+1=2张邮票,面额5有两种表示方式min(面额1+面额4,面额2+面额3)邮票数目……照此类推,递推关系方程不难建立,以下是递推的一种方法: 

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main()
     5 {
     6     freopen("stamp_data/STAMP14.in","r",stdin);
     7     freopen("stamp_data/STAMP14.txt","w",stdout);
     8     int n,m,i,j,c[256]={0},a[31001]={0};
     9     int b1=1;
    10 
    11     scanf("%d%d",&m,&n);//local test
    12     //scanf("%d%d",&n,&m);//online judge
    13     for(i=1;i<=m;i++)
    14     {
    15         scanf("%d",&c[i]);
    16         if(c[i]==1) b1=0;
    17     }
    18 
    19     if(b1==1) printf("0
    ");
    20     else
    21     {
    22         i=1; a[1]=1;//a[i]=x表示构造i这个值用x张邮票
    23         do
    24         {
    25             i++;
    26             for(j=1;j<=m;j++)
    27             {
    28                 if( (i%c[j]==0)&&( (i/c[j]<a[i]) || (a[i]==0) ))
    29                     a[i]=i/c[j];  //判断它能否被题目给定面额整除
    30             }
    31             for(j=1;j<=i/2;j++)   //寻找 1<= j <=i使得a[j]+a[i-j]值最小
    32                 if(a[j]+a[i-j]<a[i]) a[i]=a[j]+a[i-j];
    33         }while((a[i]<=n)&&(a[i]!=0));
    34         printf("%d
    ",i-1);
    35     }
    36     return 0;
    37 }

    这种递推方法原理是:对于某种要求得到的面额,判断它能否被题目给定面额整除,再寻找(1<=j<=i),使A[j]+A[i-j]值最小,求出凑成某种面额最少邮票数。

    这种递推方法虽然简单,由于1<=邮票面额<=255,1<=n<=100,因此MAX值最多可达到25500,25500次循环里必定还有嵌套循环,因此算法不加优化,很难在规定时间内得出最优值。这就需要递推的算法优化。

    进一步优化

    何不将用m种面额邮票作循环,建立递推关系式:A[i]=min(A[i-C[j]]+1),于是当取到极限值时,程序减少了约1.6*10^8次循环,递推优化作用不言而喻。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main()
     5 {
     6     freopen("stamp_data/STAMP0.in","r",stdin);
     7     freopen("stamp_data/STAMP0.txt","w",stdout);
     8     int x[256]={0},pieces[30001]={0};
     9     int n,m,i;
    10     int maxX=0;
    11     scanf("%d%d",&m,&n);  //local test
    12     //scanf("%d%d",&n,&m);  //online judge
    13     for(i=1;i<=m;i++)
    14         scanf("%d",&x[i]);
    15     do
    16     {
    17         maxX++;
    18         for(i=1;i<=m;i++)
    19         {
    20             if(maxX-x[i]>=0)
    21             {
    22                 if(pieces[maxX]==0) pieces[maxX]=pieces[maxX-x[i]]+1;
    23                 if(pieces[maxX]>pieces[maxX-x[i]]+1) pieces[maxX]=pieces[maxX-x[i]]+1;
    24             }
    25         }
    26         if(pieces[maxX]==0 || pieces[maxX]>n)
    27         {
    28             printf("%d
    ",maxX-1);
    29             break;
    30         }
    31     }while(1);
    32     return 0;
    33 }
  • 相关阅读:
    leetcode Convert Sorted List to Binary Search Tree
    leetcode Convert Sorted Array to Binary Search Tree
    leetcode Binary Tree Level Order Traversal II
    leetcode Construct Binary Tree from Preorder and Inorder Traversal
    leetcode[105] Construct Binary Tree from Inorder and Postorder Traversal
    证明中序遍历O(n)
    leetcode Maximum Depth of Binary Tree
    限制 button 在 3 秒内不可重复点击
    HTML 和 CSS 画三角形和画多边行基本原理及实践
    在线前端 JS 或 HTML 或 CSS 编写 Demo 处 JSbin 与 jsFiddle 比较
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/8408769.html
Copyright © 2011-2022 走看看