这道题很有意思,需要动一下脑筋,值得好好写篇文章
题目描述
如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 —— 就如海格告诉哈利的:“十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易。”现在,给定哈利应付的价钱P和他实付的钱A,你的任务是写一个程序来计算他应该被找的零钱。输入描述:
输入在1行中分别给出P和A,格式为“Galleon.Sickle.Knut”,其间用1个空格分隔。这里Galleon是[0, 107]]区间内的整数,Sickle是[0, 17)区间内的整数,Knut是[0, 29)区间内的整数。输出描述:
在一行中用与输入同样的格式输出哈利应该被找的零钱。如果他没带够钱,那么输出的应该是负数。输入例子:
10.16.27 14.1.28输出例子:
3.2.1
本题考点:
1.输入字符串怎么提取出数字(怎么判断字符是数字+怎么把两个数字字符搞成十进制数)
2.逗号隔开的每一个数字视为一位,两数相减,低位不够高位减一,也就是说要模拟实现减法。
思路图:
注意,输入描述中给出了GSK的范围,这个范围需要在相减的时候用到,不用刻意地在获取到输入之后马上判断范围。
定义int类型G,S,K
取数
要点:判断当前字符是不是数字 if (s[i] - '0' >= 0 && s[i] - '9' <= 0)
取数的功能做成了一个单独的函数,注意点写在注释中
void getnum(int n[3],string s) {//传进来我们用来存放数字的数组和用来提取的字符串
int carry = 0;//标记取数取到第几个
for (int i = 0; i < s.length(); i++) {;
if (s[i] - '0' >= 0 && s[i] - '9' <= 0) {//判断当前字符是不是数字
n[carry] = n[carry] * 10 + (s[i] - '0');//注意(s[i] - '0')才是我们想要的那个数字,不然会转成ASCII值
}
if (s[i] == '.') {//碰到逗号说明取完一个数
carry++;//改carry值,取下一个数
}
}
}
写完取数这个函数记得写个cout输出一下看看运作结果是否正确
第一版代码
拿了4/7的分
#include <iostream>
#include<string>
#include<vector>
using namespace std;
vector<int>vec;
void getnum(int n[3],string s) {
int carry = 0;//标记取数取到第几个
for (int i = 0; i < s.length(); i++) {;
if (s[i] - '0' >= 0 && s[i] - '9' <= 0) {
n[carry] = n[carry] * 10 + (s[i] - '0');
}
if (s[i] == '.') {//碰到逗号说明取完一个数
carry++;
}
}
}
int main() {
//输入
string str1,str2;
cin >> str1 >> str2;
//取数
int A[3] = { 0 }, B[3] = { 0 }, C[3] = { 0 };
getnum(A, str1);
getnum(B, str2);
//相减
while (B[2] < 29 && B[2] >= 0 && A[2] < 29 && A[2] >= 0) {
C[2] = B[2] - A[2];
if (C[2] < 0) {
C[2] =29+C[2];//注意29进制
B[1] -= 1;
//if (B[1] < 0)B[1] *= (-1);
}
C[1] = B[1] - A[1];
if (C[1] < 0) {
C[1] = 17+C[1];//注意17进制
B[0] -= 1;
}
C[0] = B[0] - A[0];
break;
}
for (int i = 0; i < 3; i++) {
if (i == 2)cout << C[i];
else {
cout << C[i] << '.';
}
}
return 0;
}
这边着重解释一下相减部分的意思,数组下标123分别对应GSK,数组名称AB分别对应输入例子的左右两项,数组C[3]则是我们用来记录相减结果之后要输出的数组。第一版代码中相减部分能正确实现的输入右项大于左项的情况(B-A),那如果说给的输入例子是左大于右呢?整体的代码逻辑不变,把AB位置换一下,两块用于相减的代码模块用if else设置条件隔开,最后输出的时候把C[0]的结果乘上-1就可以了。
这段相减功能的代码其实可以封装成一个函数,这样一来只要传入的形参位子交换一下就ok了,但是,考试时间有限只要能AC那就赶紧转下一题去了,得要快呀呀呀呀呀呀!好吧其实是刷题目写笔记太耗时间,手头还有论文要写,于是作罢。
完整版代码:
#include <iostream>
#include<string>
#include<vector>
using namespace std;
vector<int>vec;
void getnum(int n[3], string s) {
int carry = 0;//标记取数取到第几个
for (int i = 0; i < s.length(); i++) {
;
if (s[i] - '0' >= 0 && s[i] - '9' <= 0) {
n[carry] = n[carry] * 10 + (s[i] - '0');
}
if (s[i] == '.') {//碰到逗号说明取完一个数
carry++;
}
}
}
int main() {
//输入
string str1, str2;
cin >> str1 >> str2;
//取数
int A[3] = { 0 }, B[3] = { 0 }, C[3] = { 0 };
getnum(A, str1);
getnum(B, str2);
//相减
while (B[2] < 29 && B[2] >= 0 && A[2] < 29 && A[2] >= 0) {
if (A[0] < B[0] //左值小于右值的时候,从K向G开始算,右减左
|| (A[0] == B[0]&& A[1] < B[1])
|| (A[0] == B[0] && A[1] == B[1]&& A[2] < B[2])) {
C[2] = B[2] - A[2];
if (C[2] < 0) {
C[2] = 29 + C[2];
B[1] -= 1;
//if (B[1] < 0)B[1] *= (-1);
}
C[1] = B[1] - A[1];
if (C[1] < 0) {
C[1] = 17 + C[1];
B[0] -= 1;
}
C[0] = B[0] - A[0];
}
else {//左值大于右值的时候,左减右(也就是A-B,或者说AB互换),最后G值乘上-1
C[2] = A[2]-B[2] ;
if (C[2] < 0) {
C[2] = 29 + C[2];
A[1] -= 1;
//if (B[1] < 0)B[1] *= (-1);
}
C[1] = A[1]-B[1] ;
if (C[1] < 0) {
C[1] = 17 + C[1];
A[0] -= 1;
}
C[0] = A[0]-B[0] ;
C[0] *= -1;
}
break;
}
for (int i = 0; i < 3; i++) {
if (i == 2)cout << C[i];
else {
cout << C[i] << '.';
}
}
return 0;
}
写在最后
题目是凌晨做的,笔记写了一半扛不住了就好好睡了一觉,起来之后补完的笔记,中间有些内容可能会遗漏、或者说没写清楚什么东西,如有疑问欢迎在评论区留言探讨。