吴昊品游戏核心算法 Round 7(特刊)—— 猜数字系列(数字锁问题) 第三弹(模拟)(HDOJ 1195)
如图所示,这是一个保险箱,木有错,我们现在假设该密码有四位数,我们也知道密码的存在,我们可以基于以下的规则对这个四位数进行一系列变换,比如:
(1)可以将这个四位数的某一位上移或者下移,其中,9再往上移动便是0,而0再往下移动即是9。
(2)两个相邻的数位是可以交换(change)的,但是,有如下规则,最左边的数位不能和最右边的数位发生交换,也就是说,这两个数位,不认为是相邻的。
我们基于(1)和(2)这两个规则,要找出打开锁(也就是找到密码)需要移动的最少的次数——这里的AI,我们采用宽度优先搜索来实现(BFS+STL,可以看到,这已经是重复多遍的老战术了!对于搜索来说,这种策略确实是相当普遍的)。
问题来自HDOJ 1195,我以这个问题作为猜数字系列的完结篇。
1 /*
2 Highlights:
3 (1)用mark[11][11][11][11]存储四位数,可以方便对其进行调控
4 (2)在BFS的过程中,对于四位数的每一位,每次朝着三个可能的方向对其进行搜索,并适时标记可能的点
5 (3)初始的时候,需要判断一下是否一开始就满足条件
6 */
7
8 #include<iostream>
9 #include<string>
10 #include<queue>
11 using namespace std;
12
13 struct node
14 {
15 char digit[5];//数组尽量开大一点
16 int step;//记录次数
17 };
18
19 int mark[11][11][11][11];
20 char a[5],b[5];
21
22 void bfs()
23 {
24 int i;
25 node cur,q;
26 queue<node> Queue;
27 strcpy(q.digit,a);//将数字锁的初始值装载到q中
28 q.step=0;//初始步骤为0
29 Queue.push(q);
30 memset(mark,0,sizeof(mark));//将mark置0,从0开始搜索
31 while(!Queue.empty())
32 {
33 cur=Queue.front();//现在的结点
34 Queue.pop();
35 mark[cur.digit[0]-'0'][cur.digit[1]-'0'][cur.digit[2]-'0'][cur.digit[3]-'0']=1;
36 //四个位数
37 for(i=0;i<4;i++)
38 {
39 //加一尝试
40 strcpy(q.digit,cur.digit);
41 q.step=cur.step+1;
42 q.digit[i]=cur.digit[i]+1;
43 if(q.digit[i]='9'+1)
44 {
45 q.digit[i]='1';
46 }
47 //'0'表示还没有被visit的点,'1'表示已经标记过的点
48 if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
49 {
50 if (strcmp(q.digit, b) == 0)
51 {
52 printf("%d/n", q.step);
53 return;
54 }
55 else
56 {
57 mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
58 Queue.push(q);//进入队列
59 }
60 }
61 //减一尝试
62 strcpy(q.digit, cur.digit);
63 q.step = cur.step + 1;
64 q.digit[i] = cur.digit[i] - 1;
65 if (q.digit[i] == '0')
66 {
67 q.digit[i] = '9';
68 }
69 if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
70 {
71 if (strcmp(q.digit, b) == 0)
72 {
73 printf("%d/n", q.step);
74 return;
75 }
76 else
77 {
78 mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
79 Queue.push(q);
80 }
81 }
82 //交换尝试,由于不需要考虑首尾变换,故i<3就可以的
83 if (i < 3)
84 {
85 strcpy(q.digit, cur.digit);
86 char temp = q.digit[i];//类似于两个数交换,这里有交换数组中相邻元素的值
87 q.digit[i] = q.digit[i + 1];
88 q.digit[i + 1] = temp;
89 q.step = cur.step + 1;
90 if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
91 {
92 if (strcmp(q.digit, b) == 0)
93 {
94 printf("%d/n", q.step);
95 return;
96 }
97 else
98 {
99 mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
100 Queue.push(q);
101 }
102 }
103 }
104 }
105 }
106
107 void main()
108 {
109 int n;
110 scanf("%d",&n);//读取样例的个数
111 while(n--)
112 {
113 scanf("%s%s",a,b);
114 //运气好,刚好相等!
115 if(strcmp(a,b)==0)
116 printf("0\n");
117 else
118 bfs();
119 }
120 }
121
2 Highlights:
3 (1)用mark[11][11][11][11]存储四位数,可以方便对其进行调控
4 (2)在BFS的过程中,对于四位数的每一位,每次朝着三个可能的方向对其进行搜索,并适时标记可能的点
5 (3)初始的时候,需要判断一下是否一开始就满足条件
6 */
7
8 #include<iostream>
9 #include<string>
10 #include<queue>
11 using namespace std;
12
13 struct node
14 {
15 char digit[5];//数组尽量开大一点
16 int step;//记录次数
17 };
18
19 int mark[11][11][11][11];
20 char a[5],b[5];
21
22 void bfs()
23 {
24 int i;
25 node cur,q;
26 queue<node> Queue;
27 strcpy(q.digit,a);//将数字锁的初始值装载到q中
28 q.step=0;//初始步骤为0
29 Queue.push(q);
30 memset(mark,0,sizeof(mark));//将mark置0,从0开始搜索
31 while(!Queue.empty())
32 {
33 cur=Queue.front();//现在的结点
34 Queue.pop();
35 mark[cur.digit[0]-'0'][cur.digit[1]-'0'][cur.digit[2]-'0'][cur.digit[3]-'0']=1;
36 //四个位数
37 for(i=0;i<4;i++)
38 {
39 //加一尝试
40 strcpy(q.digit,cur.digit);
41 q.step=cur.step+1;
42 q.digit[i]=cur.digit[i]+1;
43 if(q.digit[i]='9'+1)
44 {
45 q.digit[i]='1';
46 }
47 //'0'表示还没有被visit的点,'1'表示已经标记过的点
48 if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
49 {
50 if (strcmp(q.digit, b) == 0)
51 {
52 printf("%d/n", q.step);
53 return;
54 }
55 else
56 {
57 mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
58 Queue.push(q);//进入队列
59 }
60 }
61 //减一尝试
62 strcpy(q.digit, cur.digit);
63 q.step = cur.step + 1;
64 q.digit[i] = cur.digit[i] - 1;
65 if (q.digit[i] == '0')
66 {
67 q.digit[i] = '9';
68 }
69 if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
70 {
71 if (strcmp(q.digit, b) == 0)
72 {
73 printf("%d/n", q.step);
74 return;
75 }
76 else
77 {
78 mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
79 Queue.push(q);
80 }
81 }
82 //交换尝试,由于不需要考虑首尾变换,故i<3就可以的
83 if (i < 3)
84 {
85 strcpy(q.digit, cur.digit);
86 char temp = q.digit[i];//类似于两个数交换,这里有交换数组中相邻元素的值
87 q.digit[i] = q.digit[i + 1];
88 q.digit[i + 1] = temp;
89 q.step = cur.step + 1;
90 if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
91 {
92 if (strcmp(q.digit, b) == 0)
93 {
94 printf("%d/n", q.step);
95 return;
96 }
97 else
98 {
99 mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
100 Queue.push(q);
101 }
102 }
103 }
104 }
105 }
106
107 void main()
108 {
109 int n;
110 scanf("%d",&n);//读取样例的个数
111 while(n--)
112 {
113 scanf("%s%s",a,b);
114 //运气好,刚好相等!
115 if(strcmp(a,b)==0)
116 printf("0\n");
117 else
118 bfs();
119 }
120 }
121