菜鸟记录:c语言实现PAT甲级1005--Spell It Right
Posted whf10000010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了菜鸟记录:c语言实现PAT甲级1005--Spell It Right相关的知识,希望对你有一定的参考价值。
非常简单的一题了,但还是交了两三次,原因:对数组的理解不足;对数字和字符之间的转换不够敏感。这将在下文中细说。
Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output every digit of the sum in English.
Input Specification:
Each input file contains one test case. Each case occupies one line which contains an N (≤10100).
Output Specification:
For each test case, output in one line the digits of the sum in English words. There must be one space between two consecutive words, but no extra space at the end of a line.
Sample Input:
12345
Sample Output:
one five
题目分析
输入一串数字,然后用英文表达所有数字相加和的每一位数字。
输入:10100以内的数字
输出:和的每位数字英文表达(eg:sum=256,output=two five six)
首先很明显代码是不会翻译你的结果的,所有用一个数组来存储表示每位数字的英文,其次,10100的数字不需要精准表示,因为这里也就100个数字,不是10100个数字,开始我在这卡了半天,想着数字太大要精准存储,特地翻了之前写的c语言-大数阶乘 - 1001010 - 博客园 (cnblogs.com)一文,后面发现不大行的通,审视一遍后发现了问题,最后输出,要怎么拆开数字和也是个问题。
个人想法
首先,还是从变量入手
#define MAX 100 int N,m;//输入N,用于统计N的位数m char lan[10][10] = "zero","one","two","three","four","five","six","seven","eight","nine" ; int sum,a[MAX];//计算和sum,数组a用来记录拆开的sum char n[MAX];
这里开始是想N用来输入数据,后面发现循环过程中因为不知道它的位数,所以往往遍历要很多【补:而且N作为int变量放不了100位,double型的时候可以,但sum作为int不能让N强转,都作为double时就会很麻烦】,所以在错了一次后采取了 char n[MAX]; 的写法,这样有很多的妙处:
- 可以利用字符串来进行自动分割,即在输入时不赋值在地址上(n的每位地址),scanf("%s", &n[i]); ❌ scanf("%s", &n);❌ scanf("%s", n);✔ c语言因为只接受字符,不支持string,写成这样就会自动把一串数字字符串分成单独的数字字符并赋值在每个空间单位上。
- 循环遍历时,不需要知道有几位,因为每个字符是被附在每个单位空间上的,所以这个数组遍历到空,即\'\\0\'就可以停止。
- 由于得到的是字符的地址(数字自生的ACII值),所以在计算sum时,不用强转,而是减去0的ACII值,这个差不仅是地址差也非常融洽的是数字之间的差。
到这里其实已经没有什么疑惑的点了,下面直接上完整代码。
#include<stdio.h> #define MAX 150 int N,m; char n[MAX]; char lan[10][10] = "zero","one","two","three","four","five","six","seven","eight","nine" ; int sum,a[MAX]; int main() scanf("%s", n); for (int i = 0; n[i] != \'\\0\'; i++) sum += n[i] - \'0\'; if (sum == 0)printf("zero");return 0;//如果和等于0 ,那么直接输出“zero”就行。注意,这里必须return终止,因为数组a[-1]也是0 for (int i = 0; sum; i++) a[i] = sum % 10; sum /= 10; m += 1;//m记录sum的位数,但注意数组在使用时要减1,因为超范围了 //sum最后等于0时即完成所有位数的记录,终止循环(非常巧妙) printf("%s", lan[a[m - 1]]); for(int i=m-2;i>=0;i--) printf(" %s", lan[a[i]]);//老一套输出格式,每一位的数字对于英语组记录的每一位上的英文 return 0;
总结
- 数组的利用,例如本文对英语的存储采用了二维数组,由于是char型,每单位只存放一个字符,所以lan[10][10]有10行10列,每列存放一个字符,一行存放10个字符。如果列数不足或是刚好,就会因为没有读到 \'\\0\' 而出现连续输出,如下。每列只有5个单位,故原本“seven”就该停止却因为没有 \'\\0\' 而读取到下一行“eight”一直到“nine”才停下。同样还有上文提到的数组地址。
- 字符与数字的转换。
- 停止条件的巧妙使用,如这里for循环采用sum=0停止的条件,是我个人之前没看过的。
PAT甲级 1012 The Best Rank
原题链接
题目大意
输入N个学生的学号,C语言、数学、英语三门科目的成绩,以及M个学号,对这M个学号依次输出其最好排名,以及排出最好排名的优先级最大的科目(C、M、E)或平均分(A)。如果输入的学号不在成绩列表中,输出N/A,如果不同的排名方法有相同的最好排名,输出优先级更大的科目(A>C>M>E)。
解题思路
题不难,使用结构体定义每个学生的学号和成绩信息。调用algorithm库的排序算法即可实现(对结构体类型的vector排序需要重写比较函数)。
如果两个学生的同一门科目分数相同,那么两个学生对这门课的排名应该相等,后面的学生正常排名。
示例代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct Student
string ID;
int C, M, E;//C语言分数,数学分数,英语分数,-1表示该学生不在排名中,无成绩
int A; //平均分
int best_rank; //最佳排名
int crank; //用于排序的当前排名
char best_course; //最佳排名的优先级第一位
;
bool SortC(Student s1, Student s2) return (s1.C > s2.C);
bool SortA(Student s1, Student s2) return (s1.A > s2.A);
bool SortM(Student s1, Student s2) return (s1.M > s2.M);
bool SortE(Student s1, Student s2) return (s1.E > s2.E);
bool SortID(Student s1, Student s2) return (s1.ID < s2.ID);
//对不同科目排序并更新每个学生的最好排名
void StudentSort(vector<Student> &vec, char option)
if(option=='C')//对C语言分数排序,并更新best_rank
sort(vec.begin(), vec.end(), SortC);
for(int i=0; i<vec.size(); i++)
if(vec[i].A>=0) //只遍历有分数的学生
int cur_rank; //当前排序后的排名
if(i==0 || vec[i].C!=vec[i-1].C)//当前学生的分数与上一个学生不相等
cur_rank = i+1;
vec[i].crank = cur_rank;
else //当前学生的分数与上一个学生相等,取一样的排名
cur_rank = vec[i-1].crank;
vec[i].crank = cur_rank;
if(cur_rank < vec[i].best_rank) //当前排名小于最好排名,更新最好排名和优先级科目
vec[i].best_rank = cur_rank;
vec[i].best_course = 'C';
if(cur_rank == vec[i].best_rank) //当前排名等于最好排名,根据优先级是否替换
if(vec[i].best_course=='M' || vec[i].best_course=='E')
//当前排名的课程为C,且比原来的课程优先级高,更新
vec[i].best_course = 'C';
if(option=='M')
sort(vec.begin(), vec.end(), SortM);
for(int i=0; i<vec.size(); i++)
if(vec[i].A>=0) //只遍历有分数的学生
int cur_rank = i+1; //当前排序后的排名
if(i==0 || vec[i].M!=vec[i-1].M)//当前学生的分数与上一个学生不相等
cur_rank = i+1;
vec[i].crank = cur_rank;
else //当前学生的分数与上一个学生相等,取一样的排名
cur_rank = vec[i-1].crank;
vec[i].crank = cur_rank;
if(cur_rank < vec[i].best_rank) //当前排名小于最好排名,更新最好排名和优先级科目
vec[i].best_rank = cur_rank;
vec[i].best_course = 'M';
if(cur_rank == vec[i].best_rank) //当前排名等于最好排名,根据优先级是否替换
if(vec[i].best_course=='E')
//当前排名的课程为M,且比原来的课程优先级高,更新
vec[i].best_course = 'M';
if(option=='E')
sort(vec.begin(), vec.end(), SortE);
for(int i=0; i<vec.size(); i++)
if(vec[i].A>=0) //只遍历有分数的学生
int cur_rank = i+1; //当前排序后的排名
if(i==0 || vec[i].E!=vec[i-1].E)//当前学生的分数与上一个学生不相等
cur_rank = i+1;
vec[i].crank = cur_rank;
else //当前学生的分数与上一个学生相等,取一样的排名
cur_rank = vec[i-1].crank;
vec[i].crank = cur_rank;
if(cur_rank < vec[i].best_rank) //当前排名小于最好排名,更新最好排名和优先级科目
vec[i].best_rank = cur_rank;
vec[i].best_course = 'E';
//课程E为最小优先级,不用若排名相等,不用更新
if(option=='A')
sort(vec.begin(), vec.end(), SortA);
for(int i=0; i<vec.size(); i++)
if(vec[i].A>=0) //只遍历有分数的学生
int cur_rank = i+1; //当前排序后的排名
if(i==0 || vec[i].A!=vec[i-1].A)//当前学生的分数与上一个学生不相等
cur_rank = i+1;
vec[i].crank = cur_rank;
else //当前学生的分数与上一个学生相等,取一样的排名
cur_rank = vec[i-1].crank;
vec[i].crank = cur_rank;
if(cur_rank < vec[i].best_rank) //当前排名小于最好排名,更新最好排名和优先级科目
vec[i].best_rank = cur_rank;
vec[i].best_course = 'A';
if(cur_rank == vec[i].best_rank) //当前排名等于最好排名,根据优先级是否替换
if(vec[i].best_course=='C' || vec[i].best_course=='M' || vec[i].best_course=='E')
//当前排名的课程为A,且比原来的课程优先级高,更新
vec[i].best_course = 'A';
int main()
int N, M;
vector<Student> vec;
cin >> N >> M;
for(int pos=0; pos<N; pos++)
Student s;
cin >> s.ID >> s.C >> s.M >> s.E;
s.A = (s.C+s.E+s.M) / 3;
s.best_rank = N;
vec.push_back(s);
StudentSort(vec, 'A');
StudentSort(vec, 'C');
StudentSort(vec, 'M');
StudentSort(vec, 'E');
// M次查询
for(int pos=0; pos<M; pos++)
string id;
cin >> id;
bool id_exist = false;
for(int i=0; i<vec.size(); i++)
if(id == vec[i].ID)
cout << vec[i].best_rank << " " << vec[i].best_course << endl;
id_exist = true;
break;
if(!id_exist) cout << "N/A" << endl;
return 0;
以上是关于菜鸟记录:c语言实现PAT甲级1005--Spell It Right的主要内容,如果未能解决你的问题,请参考以下文章