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