码迷,mamicode.com
首页 > 其他好文 > 详细

[模拟]ZOJ3485 Identification Number

时间:2015-04-04 11:52:25      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:

题意:给了一串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 }
ZOJ 3485

 

[模拟]ZOJ3485 Identification Number

标签:

原文地址:http://www.cnblogs.com/Empress/p/4391767.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!