标签:
题意:给了一串15位或18位的身份证号码,求 在改变最少位数的情况下, 输出正确合法的身份证号
合法的身份证 是按照以下规则:
前6位以及“Order code”三位 一定合法
其中X是根据前17位的值计算出来的 按照如下公式 (a1就是最后一位,若为10就是X)
另外 题目还规定了“Date of Birth” 要在1900.1.1到2011.4.2之间
刚开始想这题的时候,觉得15位也就只需要 改变 年月日6位
18位也就只需要 改变 年月日加X位9位而已
但是打起来发现并非这么简单。。。
单单是改变年月日就还需要考虑每月有多少天、需要考虑是否为闰年、需要考虑是否超过1900.1.1到2011.4.2的范围...
对于18位的,改变了前面 还有影响到X的
这样打下来相当之麻烦... 而且很容易错
因此不能采用这种方法
我们来换一种思路:
假设, 我们已经知道了 “在改变最少位数之后的身份证号码” 那么来计算与输入的有几位不一样,那是一件很方便的事
那么如何来得到 “在改变最少位数之后的身份证号码” 呢?
我们只需要遍历1900.1.1到2011.4.1之间的每一天 (这样想之后, 发现给了一个范围真好啊!!)
比较每一天与输入的需要改变几位,记录最小的 改变的位数 的那一天就好了
1 string s; 2 int run[2][12]={{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 3 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; 4 5 int w[]={7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1}; 6 int a[20], b[20]; 7 int ans[25]; 8 void copy(int y, int m, int d) 9 { 10 for(int i=0; i<s.length(); i++) 11 b[i]=a[i]; 12 if(s.length()==15) 13 { 14 b[6]=y%100/10, b[7]=y%100%10; 15 b[8]=m/10, b[9]=m%10; 16 b[10]=d/10, b[11]=d%10; 17 } 18 else 19 { 20 b[6]=y/1000, b[7]=y/100%10, b[8]=y%100/10, b[9]=y%100%10; 21 b[10]=m/10, b[11]=m%10; 22 b[12]=d/10, b[13]=d%10; 23 } 24 } 25 int y, m, d; 26 bool cao() 27 { 28 if(y==2011 && m==4 && d==2) 29 return true; 30 int Y=y, M=m, D=d+1; 31 if(run[((Y%4==0 && Y%100) || Y%400==0)][M-1]+1==D) 32 M++, D=1; 33 if(M==13) 34 Y++, M=1; 35 copy(Y, M, D); 36 y=Y, m=M, d=D; 37 return false; 38 } 39 40 int main() 41 { 42 int t; 43 scanf("%d", &t); 44 while(t--) 45 { 46 cin>>s; 47 for(int i=0;i<s.length();i++) 48 a[i]=(s[i]==‘X‘? 10:s[i]-‘0‘); 49 y=1900, m=1, d=1; 50 int minn=1000; 51 copy(y, m, d); 52 while(true) 53 { 54 int num=0; 55 if(s.length()==18) 56 { 57 int sum=0; 58 for(int i=0; i<17; i++) 59 sum+=b[i]*w[i]; 60 b[17]=(12-sum%11)%11; 61 } 62 for(int i=0; i<s.length(); i++) 63 if(b[i]!=a[i]) 64 num++; 65 if(num<minn) 66 { 67 for(int i=0; i<s.length(); i++) 68 ans[i]=b[i]; 69 minn=num; 70 } 71 if(cao()) 72 break; 73 } 74 for(int i=0; i<s.length(); i++) 75 { 76 if(ans[i]!=10) 77 printf("%d", ans[i]); 78 else 79 putchar(‘X‘); 80 } 81 puts(""); 82 } 83 return 0; 84 }
[模拟]ZOJ3485 Identification Number
标签:
原文地址:http://www.cnblogs.com/Empress/p/4391767.html