实验要求:
一个合法的身份证号码共18位,由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 3 4 5 6 7 8 9 10(删掉了2)
M:1 0 9 8 7 6 5 4 3 2(删掉了2对应的X)
现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。
输入、输出格式:
输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码,18位必须全部是数字。
不检验身份证前17位是否合理,只检查对前17位计算出的校验码是否与身份证第18位一致。如果一致,则输出“身份证号 passed”,否则输出“身份证号 Fail”。
输入、输出样例
1
:
具体思路:
在选取数据类型时发现int类型储存不了十八位数字,所以我选用了能储存较大数的long long类型来储存身份证号,在具体实践时关于使用switch语句,个人感觉比较麻烦,于是便思考能否将权重用一个数储存下来,以便节省自己的工作量。我通过观察发现在权重数字中存在10,如果储存在一个数中便不好对权重数字取用,但是权重数字中不存在0,于是我便构思将10转化0储存,在取用时当遇到0时说明这一位的权重是10,这样我们便得到了一个权重数字。
这些都是程序外的工作,程序内我使用for循环对身份证的前17位与权重加权求和用sum储存,再用sum对11取模得到Z的值,也就是说使用Z时就是在使用sum%11,因此我不定义Z了而直接使用sum%11,通过观察Z与M的关系我得到如下关系:
可以看到当sum%11>2时M+sum%11=12;
即M=12-sum%11;
当sum%11<2时M+sum%11=1;
即M=1-sum%11;
之后让M与身份证最后一位比较若相等则通过,不相等则不通过。
流程图:
代码实现如下:
#include<stdio.h>
int main() {
//将权重经过转化变成一个数字储存在qz中,若输入多组数据qz便需要多次使用qz所以要用一个备份储存权重
//身份证号也要经过数据处理,因此也要用备份保存起来,保证原始数据不丢失。
long long sfz,qz=79058421637905842,m,beifen,bfqz;
int sum = 0;
int n;
scanf_s("%d", &n);
for (int i = 1; i <= n; i++) {
sum = 0;
bfqz = qz;
scanf_s("%lld", &sfz);
beifen = sfz;
beifen /= 10;
for (int i = 1; i <= 17; i++) {
if(bfqz%10==0){
sum += (beifen % 10) * 10;
}
else {
sum += (beifen % 10) * (bfqz % 10);
}
bfqz /= 10;
beifen /= 10;
}
sum = sum % 11;
if (sum <=1 ) {
m = 1 - sum;
}
else if (sum > 2) {
m = 12 - sum;
}
printf("%lld", sfz);
if (m == sfz % 10) {
printf("Passed\n");
}
else {
printf("Fail\n");
}
}
return 0;
}