CDQZ_Training 2012-5-24 聪明的打字员

本文介绍了一个关于键盘操作的问题,通过广度优先搜索(BFS)算法找到从一个初始密码转换到目标密码所需的最少按键次数。文章提供了完整的代码实现,并解释了解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目OJ地址:http://cdqz.openjudge.cn/noip/1012/

 

题目摘要:

时间限制: 20000ms 内存限制:128000kB 描述:   阿兰是某机密部门的打字员,她现在接到一个任务:需要在一天之内输入几百个长度同定为6的密码。当然,她希望输入的过程中敲击键盘的总次数越少越好..     不幸的是,出于保密的需要,该部门用于输入密码的键盘是特殊设计的,键盘上没有数字键,而只有以下六个键:Swap0.Swapl,up,down,Left,Right。为了说明这6个键的作用,我们先定义录入区的6个位置的编号,从左至右依次为l,2,3,4,5,6。下面列出每个键的作用:     Swap0:按Swap0,光标位置不变,将光标所在位置的数字与录入区的l号位置的数字(左起第一个数字)交换。如果光标已经处在录入区的l号位置,则按Swap0键之后.录入区的数字不变;   Swapl:按Swapl,光标位置不变,将光标所在位置的数字与录人区的6号位置的数字(左起第六个数字)交换。如果光标已经处在录人区的6号位置,则按Swapl键之后.录人区的数字不变;   Up:按up,光标位置不变,将光标所在位置的数字加1(除非该数字是9)。例如,如果光标所在位置的数字为2,按up之后,该处的数字变为3;如果该处数字为9,则按up之后,数字不变,光标位置也不变;   down:按Down,光标位置不变,将光标所在位置的数宁减1(除非该数字是0)。如果该处数字为0,则按Down之后,数字不变,光标位置也不变;   Left:按Len,光标左移一个位置,如果光标已经在录入区的l号位置(左起笫一个位置)上,则光标不动;   Right:按Right,光标右移一个位置,如果光标已经在录入医的6号位置(左起第六个位置)上,则光标不动。当然,为了使这样的键盘发挥作用,每次录入密码之前,录入区总会随机出现一个长度为6的初始密码.而且光标固定出现在1号位置上。当巧妙地使用上述六个特殊键之后,可以得到目标密码,这时光标允许停在任何一个位置。   现在,阿兰需要你的帮助,编写一个程序,求出录人一个密码需要的最少的击键次数。 
【输入】     仪一行,含有两个长度为6的数,前者为初始密码,后者为目标密码,两个密码之间用一个空格隔开。   【输出】     仅一行,含有一个正整数,为最少需要的击键次数。   【样例输入】     123456 654321   【样例输出】     11     本题看似很难,其实是一个赤裸裸的BFS。很好处理,时间限制为2s使得不需大量加优化。参考了下钟神的程序和思路,自己终于把它写出来了。钟神的解题报告: http://www.cnblogs.com/zhonghaoxi/archive/2012/05/25/2518528.html.     常见的优化思路有三种:判重,随机化处理,双向bfs。我只采用了第一种,勉强在1s到2s之间过了。     bfs的方法是:依次进行六种操作,看是否达到目标状态,如果达到就退出,否则压入队列。     记录状态的方法有两种,可以用一个struct来存储当前密码和光标位置,也可以直接用一个7位数,最后一位代表光标位置。判重可以用布尔数组或者集合,推荐使用布尔数组。     为了方便,我们把左起第一位标记为第6位,右起第一位标记为第1位。(因为最高位在最左边,这样方便处理)这样提取六位数s第i位的方法是[s/10^(i-1)] mod 10,然后就可以轻松对这个数进行各种操作了,具体的可以看代码。   Here is the code:
View Code
  1 #include<iostream>
  2 #include<fstream>
  3 #include<queue>
  4 
  5 using namespace std;
  6 
  7 ifstream fin("typer.in");
  8 ofstream fout("typer.out");
  9 
 10 int start,end,ten[11];
 11 bool state[1000000001];
 12 
 13 struct node
 14 {
 15     int v,s;
 16 
 17     node()
 18     {
 19         v=s=0;
 20     }
 21 
 22     node(int vv,int ss)
 23     {
 24         v=vv,s=ss;
 25     }
 26 };
 27 
 28 queue<node> q;
 29 
 30 bool go_1(int v,int p,int s)
 31 {
 32     if(p==6) return false;
 33 
 34     int vnew=v;
 35     vnew=vnew-v/ten[6]*ten[6];
 36     vnew=vnew+(v/ten[p])%10*ten[6];
 37     vnew=vnew-(v/ten[p]%10)*ten[p];
 38     vnew=vnew+v/ten[6]*ten[p];
 39 
 40     if(vnew==end)
 41     {
 42         cout<<s+1<<endl;
 43         return true;
 44     }
 45 
 46     if(!state[vnew*10+p])
 47     {
 48         state[vnew*10+p]=1;
 49         q.push(node(vnew*10+p,s+1));
 50     }
 51     return false;
 52 }
 53 
 54 bool go_2(int v,int p,int s)
 55 {
 56     if(p==1) return false;
 57 
 58     int vnew=v;
 59     vnew=vnew-v%10;
 60     vnew=vnew+(v/ten[p])%10;
 61     vnew=vnew-(v/ten[p]%10)*ten[p];
 62     vnew=vnew+(v%10)*ten[p];
 63 
 64     if(vnew==end)
 65     {
 66         cout<<s+1<<endl;
 67         return true;
 68     }
 69 
 70     if(!state[vnew*10+p])
 71     {
 72         state[vnew*10+p]=1;
 73         q.push(node(vnew*10+p,s+1));
 74     }
 75     return false;
 76 }
 77 
 78 bool go_3(int v,int p,int s)
 79 {
 80     if(v/ten[p]%10==9) return false;
 81 
 82     int vnew=v+ten[p];
 83     if(vnew==end)
 84     {
 85         cout<<s+1<<endl;
 86         return true;
 87     }
 88 
 89     if(!state[vnew*10+p])
 90     {
 91         state[vnew*10+p]=1;
 92         q.push(node(vnew*10+p,s+1));
 93     }
 94     return false;
 95 }
 96 
 97 bool go_4(int v,int p,int s)
 98 {
 99     if(v/ten[p]%10==0) return false;
100 
101     int vnew=v-ten[p];
102     if(vnew==end)
103     {
104         cout<<s+1<<endl;
105         return true;
106     }
107 
108     if(!state[vnew*10+p])
109     {
110         state[vnew*10+p]=1;
111         q.push(node(vnew*10+p,s+1));
112     }
113     return false;
114 }
115 
116 bool go_5(int v,int p,int s)
117 {
118     if(p==6) return false;
119 
120     if(!state[v*10+p+1])
121     {
122         state[v*10+p+1]=1;
123         q.push(node(v*10+p+1,s+1));
124     }
125     return false;
126 }
127 
128 bool go_6(int v,int p,int s)
129 {
130     if(p==1) return false;
131 
132     if(!state[v*10+p-1])
133     {
134         state[v*10+p-1]=1;
135         q.push(node(v*10+p-1,s+1));
136     }
137     return false;
138 }
139 
140 int main()
141 {
142     cin>>start>>end;
143     if(start==end)
144     {
145         cout<<0<<endl;
146         return 0;
147     }
148     ten[1]=1;
149     for(int i=2;i<=6;i++) 
150         ten[i]=ten[i-1]*10;
151 
152     q.push(node(start*10+6,0));
153     state[start*10+6]=1;
154 
155     while(!q.empty())
156     {
157         node t=q.front();
158         q.pop();
159         int v=t.v/10,p=t.v%10,s=t.s;
160 
161         if(go_1(v,p,s)) break;
162         if(go_2(v,p,s)) break;
163         if(go_3(v,p,s)) break;
164         if(go_4(v,p,s)) break;
165         if(go_5(v,p,s)) break;
166         if(go_6(v,p,s)) break;
167     }
168 
169     return 0;
170 }

 

转载于:https://www.cnblogs.com/stickjitb/archive/2012/05/26/2519127.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值