一个合法的身份证号码由 17 位地区, 日期编号和顺序编号加 1 位校验码组成. 校验码的计算规则如下:
首先对前 17 位数字加权求和, 权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}; 然后将计算的和对 11 取模得到值 Z; 最后按照以下关系对应 Z 值与校验码 M 的值:
- Z:0 1 2 3 4 5 6 7 8 9 10
- M:1 0 X 9 8 7 6 5 4 3 2
现在给定一些身份证号码, 请你验证校验码的有效性, 并输出有问题的号码.
输入格式:
输入第一行给出正整数 N(≤) 是输入的身份证号码的个数. 随后 N 行, 每行给出 1 个 18 位身份证号码.
输出格式:
按照输入的顺序每行输出 1 个有问题的身份证号码. 这里并不检验前 17 位是否合理, 只检查前 17 位是否全为数字且最后 1 位校验码计算准确. 如果所有号码都正常, 则输出 All passed.
输入样例 1:
- 4
- 320124198808240056
- 12010X198901011234
- 110108196711301866
- 37070419881216001X
输出样例 1:
- 12010X198901011234
- 110108196711301866
- 37070419881216001X
输入样例 2:
- 2
- 320124198808240056
- 110108196711301862
输出样例 2:
All passed
解题思路:
(1) 遍历输入的字符串:
1如果当前字符是字母, 直接输出, 并且置有错的标识 flag=1, 输出当前字符串并结束字符串的遍历循环.
2如果是数字, 就乘上权重加到 sum 上
(2) 遍历完之后, 如果是没有碰到字母的情况就对 sum%11 的结果对应的字符是否和第 18 位的字符是否相等进行判断, 否则继续读取下一个字符串
(3) 最后对是否有错误数据的 flag 进行判断, 如果 flag =0, 即没有错误数据, 就输出 "All passed"
对 break 和 continue 做个总结:
break 作用是: 彻底结束循环, 例如本题代码中碰到字母的情况, 出现一个字母就说明出错了, 不用继续遍历接下来的字母了, 所以用 break 结束本次字符串的遍历.
continue 作用是: 结束本次循环, 也就是本次循环在 continue 之后的语句不会执行, 但是会继续下一次的循环, 例如本题中如果遍历字符串的过程中出现了字母, 那么就不用对 sum 的结果进行处理, 但是还需要继续读取下一个字符串, 所以用到 continue 来结束本次循环.
return 语句可以用来退出双层循环, 但是 return 完整个方法也会结束
- #include<iostream>
- using namespace std;
- // 权重
- int rate [17] = { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 };
- // 关系表示
- char m [12] = "10X98765432";
- int main () {
- int n;
- cin>> n;
- int i, sum, flag = 0;//sum 表示前 17 位的和, flag 表示是否有数据错误
- char id [18];// 身份证号
- while ( n-- ) {
- cin>> id;
- for ( i = 0, sum = 0; i <17; i++ ) {
- if ( id [i]>= '0'&& id [i] <= '9' ) {
- // 遇到数字的情况
- sum += ( rate [i] * ( id [i] - '0' ) );
- }
- else {
- // 碰到字母
- cout << id << endl;
- flag = 1;// 有遇到错误数据
- break;
- }
- }
- // 如果不是最后一位数据, 即中间遇到了字母, 不执行接下来的代码, 继续下一次循环
- if ( i < 17 ) continue;
- if ( m [sum % 11] != id [17] ) {
- // 校验码不一致
- cout << id << endl;
- flag = 1;
- }
- }
- // 如果没有数据错误
- if ( flag == 0 ) {
- cout << "All passed" << endl;
- }
- system ( "pause" );
- return 0;
- }
来源: http://www.bubuko.com/infodetail-3486375.html