栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

初级c语言练题之路day 1

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

初级c语言练题之路day 1

(前面都是诡异的尝试,好写的办法在后面)

昨天机试挂了一道题,长成这样:

现在有两种面值的邮票,一种为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(* ̄▽ ̄*)ブ:

#include
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 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;
}

果然过了,φ(゜▽゜*)♪。但是好像也没有比双重循环好多少,不管了,好歹是自己优化出来的!而且时间复杂度要好不少,虽然还不知道怎么广泛一点,但是好耶!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/873423.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号