题目描述
高桥君为了准备即将到来的7月27日土用丑日,打算邮购一些高级鳗鱼食材,通过网上银行来支付。 高桥君使用的银行卡背面有下图所示的9×9密码表。支付的时候从表中某一位置开始根据指定的方向连续读4个数字作为验证码输入,验证是否是本人操作。 下图的例子是从左边第一列,上方第一行开始,按斜右下的方向连续读4个数字。此时读出来的数字是7930.
如果读数的过程中超过了边界,就要将方向改变,然后继续读剩余的数字。改变方向的规则如下:
- 原方向是上下左右时
- 将原方向180°调转
- 原方向是斜向时
- 在对角线上时:将原方向180°调转
- 遇到左右边界时:上下方向不变,左右方向调转
- 遇到上下边界时:左右方向不变,上下方向调转
给出密码表、起始位置和方向,要求输出相应的4位验证码。
输入输出格式
输入格式:
- 共10行输入
- 第1行,整数x代表列(1≤x≤9),整数y代表行(1≤y≤9),W表示方向
- W是R、L、U、D、RU、RD、LU、LD的其中一种
- R:右方向
- L:左方向
- U:上方向
- D:下方向
- RU:右上方向
- RD:右下方向
- LU:左上方向
- LD:左下方向
- 第2行到第9行是密码表中的整数C[i][j](1≦i,j≦9)
- i和j表示第i行第j列数字C[i][j]
- Cij的范围是0到9
输出格式:
输出一行四个整数,最后输出换行。
题目分析:
这是一道模拟题。我们需要根据给出的密码本和位置读出结果。这道题看似简单,但是维护转弯操作是一个很复杂的过程。
首先在读入的时候就存在问题。读入的起始位置是先读入列后读入行,因此我设x为行,y为列,然后先输入的y后输入的x。读入密码本的时候两个数字之间并没有空格,这就使得我们不能通过直接cin的方式进行读入。我使用了scanf读入方式中的操作
scanf("%1d",&mp[i][j]);
这种操作保证了每一次只会读入一位数,避免出现连读的现象。
在读入之后我们需要维护每一个运动的方向。这里我使用的是string来存储每一个方向的名字,因为有些方向存在多个字符;然后我用了两个map来分别存储往每一个方向前进一步时,行的变化量和列的变化量。代码如下:
#include<map>
#include<string>
map<string,int>h1,h2;
int main(){
h1["R"]=0;h2["R"]=1;h1["L"]=0;h2["L"]=-1;h1["U"]=-1;h2["U"]=0;
h1["D"]=1;h2["D"]=0;h1["RU"]=-1;h2["RU"]=1;h1["LU"]=-1;h2["LU"]=-1;
h1["RD"]=1;h2["RD"]=1;h1["LD"]=1;h2["LD"]=-1;
}
在初始化完每一个方向的位置变化量后要进行输出操作。一共要输出四个数,每输出一个数后进行一次位置的变化,只需要将x和y分别加上map中存储好的位置变化量即可。但是这样有可能会出现出界的问题。
为了避免出界,每一次位置的移动之后都需要对当前的位置是否在界内进行一次判断。这里只要写一个函数,判断当前x和y是否在1到9之间即可。如果不在界内则需要转弯。代码的实现如下:
1 bool chujie(){
2 if(x<=0||x>=10||y<=0||y>=10){
3 return false;
4 }else{
5 return true;
6 }
7 }
8 int main(){
9 for(int i=1;i<=4;i++){
10 cout<<mp[x][y];
11 x+=h1[w];y+=h2[w];
12 if(chujie()==false){
13 zhuan();
14 }
15 }
16 cout<<endl;
17 return 0;
18 }
这样我们就只剩下完善转弯函数zhuan()了。
虽然运动的方向一共有8种,但是其中的向上、向下、向左、向右四种情况是很容易解决的。因为这四种情况根据题意,只需要调转方向,同时将读数位置向转后的方向倒退回去即可。
当方向为剩下四种时,情况就多样了。总的可以分为两大类,一类是撞在了四个边界上,另一类是撞在了四个对角线上。
当撞在对角线上时,根据题意,要调转方向,同时向调转后的方向倒退。这里要注意两点:第一,撞每一个对角线时撞上去的方向是固定的,绝不会出现往左下走而撞到右下角的情况,因此判断是否撞到了四个对角线的最好方式是判断坐标。第二,在判断坐标时,应当判断x和y是否等于已出界的坐标(如撞上左上角时应判断是否满足x==0&&y==0,而非x==1&&y==1),因为此时x和y已在界外。
当撞在边界上时,由于要求将原方向旋转90°,所以撞到不同边界时旋转的变化方向是不同的,因而要判断究竟撞上了哪个边界。因为已经排除了对角线的特殊情况,所以只需要判断x或y一个位置即可。判断后,每一个边界也只有两个方向能撞上,分别处理即可。
最后要注意一点,在判断以上的所有情况时都是else if,而不是if。否则会出现重复转方向问题。
最后是完整代码,注意其中的转弯函数。
1 #include<iostream>
2 #include<map>
3 #include<cstdio>
4 #include<string>
5 using namespace std;
6 int x,y;
7 string w;
8 int mp[10][10];
9 map<string,int>h1,h2;
10 bool chujie(){
11 if(x<=0||x>=10||y<=0||y>=10){
12 return false;
13 }else{
14 return true;
15 }
16 }
17 void zhuan(){//改变方向
18 if(w=="U"){//原方向向上
19 x+=2;w="D";
20 }else if(w=="D"){
21 x-=2;w="U";
22 }else if(w=="L"){
23 y+=2;w="R";
24 }else if(w=="R"){
25 y-=2;w="L";
26 }else{
27 if(w=="LU"&&x==0&&y==0){//先处理对角线
28 x+=2;y+=2;w="RD";
29 }else if(w=="LD"&&x==10&&y==0){
30 x-=2;y+=2;w="RU";
31 }else if(w=="RU"&&x==0&&y==10){
32 x+=2;y-=2;w="LD";
33 }else if(w=="RD"&&x==10&&y==10){
34 x-=2;y-=2;w="LU";
35 }else if(y==10){//撞右边界
36 if(w=="RU"){
37 y-=2;w="LU";
38 }else if(w=="RD"){
39 y-=2;w="LD";
40 }
41 }else if(y==0){//撞左边界
42 if(w=="LU"){
43 y+=2;w="RU";
44 }else if(w=="LD"){
45 y+=2;w="RD";
46 }
47 }else if(x==0){//撞上边界
48 if(w=="LU"){
49 x+=2;w="LD";
50 }else if(w=="RU"){
51 x+=2;w="RD";
52 }
53 }else if(x==10){//撞下边界
54 if(w=="RD"){
55 x-=2;w="RU";
56 }else if(w=="LD"){
57 x-=2;w="LU";
58 }
59 }
60 }
61 }
62 int main(){
63 cin>>y>>x>>w;//x是行,y是列
64 for(int i=1;i<=9;i++){
65 for(int j=1;j<=9;j++){
66 scanf("%1d",&mp[i][j]);
67 }
68 }
69 h1["R"]=0;h2["R"]=1;h1["L"]=0;h2["L"]=-1;h1["U"]=-1;h2["U"]=0;
70 h1["D"]=1;h2["D"]=0;h1["RU"]=-1;h2["RU"]=1;h1["LU"]=-1;h2["LU"]=-1;
71 h1["RD"]=1;h2["RD"]=1;h1["LD"]=1;h2["LD"]=-1;
72 for(int i=1;i<=4;i++){
73 cout<<mp[x][y];
74 x+=h1[w];y+=h2[w];
75 if(chujie()==false){
76 zhuan();
77 }
78 }
79 cout<<endl;
80 return 0;
81 }