C语言程序设计100例之(80):ISBN 号码
例80 ISBN 号码
问题描述
每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字、1位识别码和3位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-就是分隔符(键盘上的减号),最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。ISBN码的首位数字表示书籍的出版语言,例如0代表英语;第一个分隔符-之后的三位数字代表出版社,例如670代表维京出版社;第二个分隔符后的五位数字代表该书在该出版社的编号;最后一位为识别码。
识别码的计算方法如下:
首位数字乘以1加上次位数字乘以2……以此类推,用所得的结果mod11,所得的余数即为识别码,如果余数为10,则识别码为大写字母X。例如ISBN号码0-670-82162-4中的识别码4是这样得到的:对067082162这9个数字,从左至右,分别乘以1,2,...,9再求和, 0×1+6×2+……+2×9=158,然后取158 mod 11的结果4作为识别码。
你的任务是编写程序判断输入的ISBN号码中识别码是否正确,如果正确,则仅输出Right;如果错误,则输出你认为是正确的ISBN号码。
输入
一个字符序列,表示一本书的ISBN号码(保证输入符合ISBN号码的格式要求)。
输出
一行,假如输入的ISBN号码的识别码正确,那么输出Right,否则,按照规定的格式,输出正确的ISBN号码(包括分隔符-)。
输入样例
0-670-82162-0
输出样例
0-670-82162-4
(1)编程思路。
简单的字符串模拟题。用循环对字符串中的前11个字符进行处理,计算出识别码与最后一个字符比较,根据比较结果输出相应信息。
(2)源程序。
#include <stdio.h> int main() { char isbn[14],ch; int i,k,s; scanf("%s",isbn); for (i=0,k=0,s=0;i<=10;i++) if (isbn[i]!='-') { k++; s+=k*(isbn[i]-'0'); } if (s%11==10) ch='X'; else ch=(s%11)+'0'; if (isbn[12]==ch) printf("Right\n"); else { isbn[12]=ch; printf("%s\n",isbn); } return 0; }
将此源程序提交给洛谷OJ题库 P1055 ISBN 号码(https://www.luogu.com.cn/problem/P1055)可以Accepted。
习题80
80-1 信用卡号的验证
问题描述
当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证通过。
该校验的过程:
1、从卡号最后一位数字开始,逆向将奇数位(1、3、5等等)相加。
2、从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去9),再求和。
3、将奇数位总和加上偶数位总和,结果应该可以被10整除。
例如,卡号是:5432123456788881
则奇数位和=35
偶数位乘以2(有些要减去9)的结果:1 6 2 6 1 5 7 7,求和=35。
最后35+35=70 可以被10整除,认定校验通过。
请编写一个程序,从键盘输入卡号,然后判断是否校验通过。通过显示:“Right”,否则显示“Wrong”。
输入
一串信用卡号。
输出
判断结果。
输入样例
356827027232780
输出样例
成功
(1)编程思路。
简单的字符串模拟题,用循环对字符串按题目要求进行处理。
(2)源程序。
#include <stdio.h> #include <string.h> int main() { char s[26]; scanf("%s",s); int sum=0,t; int i,f; for (i=strlen(s)-1,f=1;i>=0;i--,f=1-f) { if (f==1) sum+=s[i]-'0'; else { t=2*(s[i]-'0'); if (t>9) t-=9; sum+=t; } } if (sum%10==0) printf("Right\n"); else printf("Wrong\n"); return 0; }
80-2 宝石串
问题描述
有一种宝石串,由绿宝石和红宝石串成,仅当绿宝石和红宝石数目相同的时候,宝石串才最为稳定,不易断裂。安安想知道从给定的宝石串中,可以截取一段最长的稳定的宝石串,有多少颗宝石组成。请你帮助他。
绿宝石用‘G’表示,红宝石用‘R'表示。
输入
一行由G和R组成的字符串
输出
最长的稳定的宝石串有多少颗宝石组成
输入样例
GRGGRG
输出样例
4
(1)编程思路。
定义两个数组int a[1000001],b[1000001];,其中a[i]和b[i]分别表示前一个宝石中绿宝石和红宝石的个数,初始值全部为0。
用循环对宝石串进行扫描处理,计算出数组a和b各元素的值。
之后对区间[i,j](区间左端点从1~n,n为宝石串中宝石的个数;右端点从n~i)进行处理,若在某段区间中,绿宝石的个数a[j]-a[i-1]和红宝石的个数b[j]-b[i-1]相等,则这段区间中的宝石可以构成稳定的宝石串,穷举找到最长的区间即可。
(2)源程序。
#include <stdio.h> int a[1000001],b[1000001]; int main() { char str[1000001]; scanf("%s",str); a[0]=b[0]=0; int i,j; for (i=1;str[i-1]!='\0';i++) { if (str[i-1]=='G') { a[i]=a[i-1]+1; b[i]=b[i-1]; } else { b[i]=b[i-1]+1; a[i]=a[i-1]; } } int n=i-1; if (a[n]==0 || b[n]==0) { printf("0\n"); return 0; } int ans=0; for (i=1;i<=n;i++) // 区间左端点 { if (n-i+1<ans) break; for (j=n;j>=i;j--) { if (j-i+1<=ans) break; if (a[j]-a[i-1]==b[j]-b[i-1]) if (ans<j-i+1) ans=j-i+1; } } printf("%d\n",ans); return 0; }
将此源程序提交给洛谷OJ题库 P2697 宝石串(https://www.luogu.com.cn/problem/P2697)可以Accepted。
80-3 方便记忆的电话号码
问题描述
英文字母(除Q和Z外)和电话号码存在着对应关系,如下所示:
A,B,C -> 2
D,E,F -> 3
G,H,I -> 4
J,K,L -> 5
M,N,O -> 6
P,R,S -> 7
T,U,V -> 8
W,X,Y -> 9
标准的电话号码格式是xxx-xxxx,其中x表示0-9中的一个数字。有时为了方便记忆电话号码,我们会将电话号码的数字转变为英文字母,如把263-7422记成America。有时,我们还加上“-”作为分隔符,如把449-6753记成Hi-World。当然,我们未必要将所有的数字都转变为字母,比如474-6635可以记成iPhone-5。
总之,一个方便记忆的电话号码由数字和除Q、Z外的英文字母组成,并且可以在任意位置插入任意多的“-”符号。
现在 ,我们有一个列表,记录着许多方便记忆的电话号码。不同的方便记忆的电话号码可能对应相同的标准号码,你的任务就是找出它们。
输入
第一行是一个正整数n(n <= 100000),表示列表中的电话号码数。
其后n行,每行是一个方便记忆的电话号码,它由数字和除Q、Z外的英文字母、“-”符号组成,其中数字和字母的总数一定为7,字符串总长度不超过200。
输出
输出包括若干行,每行包括一个标准电话号码(xxx-xxxx)以及它重复出现的次数k(k >= 2),中间用空格分隔。输出的标准电话号码需按照升序排序。
如果没有重复出现的标准电话号码,则输出一行“No duplicates.”。
输入样例
12
4873279
ITS-EASY
888-4567
3-10-10-10
888-GLOP
TUT-GLOP
967-11-11
310-GINO
F101010
888-1200
-4-8-7-3-2-7-9-
487-3279
输出样例
310-1010 2
487-3279 4
888-4567 3
(1)编程思路。
编写函数int ctoi(char ch),按英文字母(除Q和Z外)和电话号码存在的对应关系,把字符ch转换为对应的数字。
输入时将所有的电话号码全部转换为全部由7位数字表示的电话号码后进行保存,去掉输入中的连接符“-”,将字母全部转换为对应的数字。
将保存好的电话号码按整数从小到大排列,这样相同的号码一定会排列在一起,用循环对排序好的数组进行扫描处理,重复次数超过2的电话号码按要求格式输出。
(2)源程序。
#include <stdio.h> #include <algorithm> using namespace std; int ctoi(char ch) // 把字符ch转换为对应的数字 { if(ch=='A' || ch=='B' || ch=='C') return 2; if(ch=='D' || ch=='E' || ch=='F') return 3; if(ch=='G' || ch=='H' || ch=='I') return 4; if(ch=='J' || ch=='K' || ch=='L') return 5; if(ch=='M' || ch=='N' || ch=='O') return 6; if(ch=='P' || ch=='R' || ch=='S') return 7; if(ch=='T' || ch=='U' || ch=='V') return 8; if(ch=='W' || ch=='X' || ch=='Y') return 9; if (ch>='0' && ch<='9') return ch-'0'; } int main() { int n; //号码数 scanf("%d",&n); int out[100001]; // 存放待输出的电话号码 int num,i,j; for(i=0;i<n;i++) { num=0; char s[201]; scanf("%s",s); for (j=0;s[j]!='\0';j++) { if(s[j]=='-' || s[j]=='Q' || s[j]=='Z') continue; num=num*10+ctoi(s[j]); } out[i]=num; } sort(out,out+n); int flag=1; // 标记是否所有号码都是唯一的 i=0; while (i<n) { int times=0; // out[i]出现的次数 int k=out[i]; int sign=0; // 标记k出现次数是否大于2 while (i<n && k==out[i]) { times++; i++; if(times==2) { flag=0; sign=1; } } if (sign) { printf("%03d-%04d %d\n",k/10000,k%10000,times); } } if (flag) printf("No duplicates.\n"); return 0; }
将此源程序提交给北大OJ题库 POJ 1002 487-3279(http://poj.org/problem?id=1002)可以Accepted。