(前面都是诡异的尝试,好写的办法在后面)
昨天机试挂了一道题,长成这样:
现在有两种面值的邮票,一种为8角,一种为6角。你要付n角的邮资(不能多付也不能少付),请给出邮票张数最少的方案。如果没有正好的方案则输出-1。
输入格式:
只有一行,为若干个整数(至少有两个)。这些整数最后一个整数一定是-1(输入结束标志,无需处理),其他整数均大于0,这些大于0的整数代表邮资。
输出格式:
若干行,每行依次对应输入的一个邮资,如果该邮资有正好的方案,则为两个用空格分隔的整数,代表张数最少的方案。前边的数字代表需要的8角的邮票的张数,后边的数字代表6角的邮票的张数;如果该邮资没有正好的方案则输出-1。测试用例保证所有整数均可以用int存储。。
大佬眼中这自然是一道水题,但是在下水平有限,考试的时候脑子一热选择了诡异的算法
如下图所示:
#include#include using namespace std; int main(){ int n; int a=8,b=6; int ans1=0,ans2=0,sum=0; while(scanf("%d",&n)){ if(n==-1){ return 0; break; } int n0=n; while(n0>=2){ n0-=2; } if(1==n0){ printf("-1n"); continue; } else{ int biao=0; if(n<6){ printf("-1n"); continue; } else{ sum=0; ans1=0; ans2=0; while(sum 写了四十分钟,又臭又长,而且循环写到后面的时候自己都不知道在干什么了。连数据初始化的位置都忘了,最后把初始化写得到处都是。提交之后过了一组数据,但是头痛欲裂,实在不想再翻回去改这一坨不明物体。 改这东西过于折磨,不如重写,于是反手删完,从头开始。崭新代码如下
#include#include #include using namespace std; int ans1=0,ans2=0,sum=0; int cha(int n,int m){ if(n<0){ printf("-1n"); ans1=0;ans2=0;sum=0; return 0; } int n0=n; while(sum 似乎比之前好了一点,现在过了四组数据,那就稍微改一改。既然能对四组,说明整体的问题是不大的,合理怀疑在小数据的某种特殊情况出现了问题。于是我把n从1循环到100来找bug。然后在输出的数据中看见了一组非常扎眼的数据n=10 ans1=-1 ans2=3。
这玩意儿怎么还给我搞出负数来了!(メ▼へ▼)/?{︻┻┳═一
这么一想,不断的循环减数,确实容易整出负号来。于是添加了一组判断ans1 是否合法的判断。终于过了!代码如下:
#include#include #include using namespace std; int ans1=0,ans2=0,sum=0; int cha(int n,int m){ if(n<6){ printf("-1n"); ans1=0;ans2=0;sum=0; return 0; } int n0=n; while(sum =1){ sum-=8; ans1--; } else{ printf("-1n"); return 0; } n0=sum; while(sum 还是又臭又长,而且明明刚刚学完循环和数组,按理来讲不会整出这种花活啊,怎么就整出来这一串呢?╮( ̄▽ ̄")╭
再次思考了一下,查了查题解,试了试一个单纯一点的办法,比如双重循环:
while(scanf("%d",&n)){ if(n==-1){ break; } for(int i=n/8;i>=0;--i){ for(int j=n/6;j>=0;j--){ if(8*i+6*j==n){ printf("%d %dn",i,j); count++; sign=1; } } if(sign==1){ sign=0; break; } } if(count==0){ printf("-1n"); } count=0; }一次就过了(○´・д・)!!!所以我之前到底在干什么。⊙ˍ⊙。为什么好好的一道题会整成这样。既然都已经走到了这一步,不如再思考一番这道题还能不能再好搞一点。于是我输出了1000以内的所有数,除开奇数之外,从12开始的所有偶数都可以被表出。于是我猜想12以后的所有偶数都能写成6,8的组合。想要证明这一点是容易的。由于24是6,8的公因数,每当贴上4张6角总是可以用3张8角代替,所以只考虑6角的张数在0~3。
不妨设2n可以被6,8表示,往证2n+2可以被6,8表示。
不妨设2n=8a+6b,2n+2=8(a-2)+6(b+3);当a<=2时的数可以被验证。由数学归纳法就知道了一个大于12的偶数确实总可以被6,8表示,而奇数总是不能被表示的。
那么,6角的张数总是0~3,这个范围是非常小的,因此对于大于12的任意的一种偶数邮资,总是可以写成8a,8a+6,8a+12,8a+18三种情况。在知道这个之后问题一下子变得简单了起来,对于任意的一个邮资,如果<=12,不是6,8就直接输出-1;>=12,奇数自然直接输出-1,偶数只要按序遍历以上4种情况,自然可以得到答案。这样,我就得到了一份简单的代码o(* ̄▽ ̄*)ブ:
#includeusing namespace std; int main(){ int n,m=0; while(scanf("%d",&n)){if(n==-1) break; m=0; if(n<12){ if(n==6) printf("0 1n"); if(n==8) printf("1 0n"); if(n!=6&&n!=8) printf("-1n"); } else{ if(n%2==1){ printf("-1n"); continue; } while(m<=3){ if((n-6*m)%8==0){ printf("%d %dn",(n-6*m)/8,m); break; } m++; } } } return 0; } 果然过了,φ(゜▽゜*)♪。但是好像也没有比双重循环好多少,不管了,好歹是自己优化出来的!而且时间复杂度要好不少,虽然还不知道怎么广泛一点,但是好耶!



