目录
题目描述
我国国标〖GB 11643-1999〗中规定:公民身份号码是18位特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。其校验码(最后一位)计算方法和步骤为:
(1)十七位数字本体码加权求和公式
S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
其中Ai:表示第i位置上的身份证号码数字值
Wi:表示第i位置上的加权因子,前17位加权因子从左到右分别为
Wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
(2)计算模
Y = mod(S, 11)
(3)通过模Y查下表得到对应的校验码
Y | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
校验码 | 1 | 0 | X | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
例如:某身份证前17位为11010519491231002
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
wi | 7 | 9 | 10 | 5 | 8 | 4 | 2 | 1 | 6 | 3 | 7 | 9 | 10 | 5 | 8 | 4 | 2 |
1 | 1 | 0 | 1 | 0 | 5 | 1 | 9 | 4 | 9 | 1 | 2 | 3 | 1 | 0 | 0 | 2 | |
积 | 7 | 9 | 0 | 5 | 0 | 20 | 2 | 9 | 24 | 27 | 7 | 18 | 30 | 5 | 0 | 0 | 4 |
得到和为:167;则模为y=167%11=2
查(3)得校验码为X(大写)
请按上面所述步骤编程,输入一个二代身份证号,检查该身份证是否正确。
【输入形式】
输入若干行,每行一个身份证号码,最后一行输入-1
【输出形式】
输出1代表正确,0代表错误
【样例输入】
120223198902021249
130132199210293822
130402198207290622
-1
【样例输出】
1 1 0
问题分析及边界条件
要处理的问题
计算校验码分为三步。随后,比较输入身份证号码的最后一位与计算出来的正确值是否相同
1、用全局数组int weight[17]记录前17位数字对应的权值因子,int code[2][11]记录Y值与校验码的对应关系。
2、求加权和
3、取模
4、查表
5、比对。注意特殊情况’X‘。
边界条件:无
算法设计
1、由于有若干组数据,采用while+cin模式输入。注意每次输入的是一个string。
2、计算加权和时,采用下标访问string中的每个字符(注意区分单个字符(比如’#‘、’5‘)跟长度为1的字符串(比如“1”、“H”)),并利用’1‘与1 ASCII码的关系求出加权和,
3、取模求出Y后,遍历code数组查表得出正确的校验码。需要注意的是,由于code中元素类型是int,’X‘会被转成int型,为整数88。最后比对时要单独讨论这种情况。
4、比对,输出结果。
AC代码
#include <iostream>
#include<stdio.h>
#include<string>
using namespace std;
int weight[17]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
int code[2][11]=
{
0,1,2,3,4,5,6,7,8,9,10,
1,0,'X',9,8,7,6,5,4,3,2
};
int arr[20]={0};
int main()
{
string s;
while((cin >> s) && (s[0]!='-'))
{
int sum=0;
for(int i=0;i<17;i++)
{
sum+=((s[i]-'0')*weight[i]);
}
int Y=0;
Y=sum%11;
for(int i=0;i<11;i++)
{
if(code[0][i]==Y)
{
Y=code[1][i];
break;
}
}
if(Y==88)//特殊处理一下
{
if(s[17]=='X')
{
printf("1\n");
}
else
{
printf("0\n");
}
}
else//一般情况:
{
if((s[17]-'0')==Y)
{
printf("1\n");
}
else
{
printf("0\n");
}
}
}
return 0;
}
总结
应用通过下标访问string的方法。