题目链接:
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\n");
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\n",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\n",maxX-1);
29 break;
30 }
31 }while(1);
32 return 0;
33 }