【CCF CSP-20131202】ISBN 号码

题意概述

每一本正式出版的图书都有一个 ISBN 号码与之对应,ISBN 码包括 9 位数字、1 位识别码和 3 位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-是分隔符(键盘上的减号),最后一位是识别码。识别码的计算方法如下:

首位数字乘以 1 加上次位数字乘以 2……以此类推,用所得的结果 mod 11,所得的余数即为识别码,如果余数为 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 号码(包括分隔符-)。

时间

​ 2025年2月28日20:37:09

C++代码

C++代码1:

算法思路:观察ISBN手动模拟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 错误代码:
#include<iostream>
#include<string>
using namespace std;

int main(){
string num;
cin>>num;
// x-xxx-xxxxx-x
// 0-234-678910-12
int x = 1 * (num[0] - '0') // 第1位字符转数字
+ 2 * (num[2] - '0') // 第3位字符转数字
+ 3 * (num[3] - '0') // 第4位字符转数字
+ 4 * (num[4] - '0') // 第5位字符转数字
+ 5 * (num[6] - '0') // 第7位字符转数字
+ 6 * (num[7] - '0') // 第8位字符转数字
+ 7 * (num[8] - '0') // 第9位字符转数字
+ 8 * (num[9] - '0') // 第10位字符转数字
+ 9 * (num[10] - '0'); // 第11位字符转数字
x%=11;
if(x==num[12]-'0') // 这里有问题!没有检查X。
cout<<"Right";
else{
num[12]=x==10?'X':x+'0';
cout<<num;
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 正确代码
#include<iostream>
#include<string> // 必须包含string头文件以使用string类型
using namespace std;

int main(){
string num;
cin >> num;

// 计算ISBN加权和(格式:x-xxx-xxxxx-x)
int x = 1 * (num[0] - '0') // 第1位数字(索引0)
+ 2 * (num[2] - '0') // 第2组第1数字(索引2)
+ 3 * (num[3] - '0') // 第2组第2数字(索引3)
+ 4 * (num[4] - '0') // 第2组第3数字(索引4)
+ 5 * (num[6] - '0') // 第3组第1数字(索引6)
+ 6 * (num[7] - '0') // 第3组第2数字(索引7)
+ 7 * (num[8] - '0') // 第3组第3数字(索引8)
+ 8 * (num[9] - '0') // 第3组第4数字(索引9)
+ 9 * (num[10] - '0'); // 第3组第5数字(索引10)
x %= 11; // 取模11得到校验值

// 解析原始校验码(需处理'X'情况)
char original = num[12];
int check = (original == 'X' || original == 'x') ? 10 : original - '0';

// 校验并输出结果
if (x == check) { // 校验通过
cout << "Right";
} else { // 校验不通过
num[12] = (x == 10) ? 'X' : x + '0'; // 生成正确校验码
cout << num;
}
return 0;
}

C++代码2:

算法思路:

  1. ISBN校验算法实现
    实现典型ISBN-10校验码计算规则:加权系数从1递增,模11校验
  2. 智能字符处理
    • si[i] - '0' 实现字符数字到整型转换
    • sum % 11 + '0' 反向转换时自动处理ASCII映射
  3. 边界处理优化
    循环条件 i < si.size() - 1 跳过最后一位校验码
  4. 内存效率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <bits/stdc++.h>  // 包含所有标准库头文件(竞赛编程常用写法)

using namespace std;
using ll = long long; // 定义长整型别名,便于处理大数

int main() {
// 优化输入输出速度(关闭与C标准库的同步)
ios::sync_with_stdio(false);
cin.tie(0);

string si; // 存储输入的字符串(如ISBN号码)
cin >> si; // 读取输入

ll num = 1; // 权重计数器,从1开始递增
ll sum = 0; // 加权求和结果

// 遍历字符串前n-1个字符(假设最后一位是校验码)
for (ll i = 0; i < si.size() - 1; ++i) {
if (isdigit(si[i])) { // 只处理数字字符
// 累加:数字值 × 当前权重,权重递增
sum += (si[i] - '0') * (num++);
}
}

// 计算校验码:当余数为10时用'X'表示,否则转成字符数字
char c = sum % 11 == 10 ? 'X' : sum % 11 + '0';

// 校验判断
if (si.back() == c) { // 校验码正确
cout << "Right\n";
} else { // 校验码错误
si.back() = c; // 替换为正确校验码
cout << si; // 输出修正后的完整字符串
}

return 0;
}