AT212 P-CASカードと高橋君
题目描述
高橋君は来る 7 月 27 日の土用の丑の日に備えて、高級なうなぎを通販で買うことにしました。支払いはネット銀行を通して行います。
高橋君が利用しているネット銀行のカードの裏には、下図のような縦 9 文字 ×横 9 文字の数字から成る乱数表がついています。支払う時は、この乱数表の指定された位置から縦横斜めの中で指定された向きに 4 文字連続で抜き出して入力し、それが正しいかによって本人確認を行います。
下図は「上から 1 文字目、左から 1 文字目」の位置から「右下斜め」の方向が指定された時の 4 文字を抜き出した例です。この場合は 7930 が入力する数字になります。
![](https://img2020.cnblogs.com/blog/1691646/202008/1691646-20200828103351661-2089681007.png)
図: 1 行目 1 文字目から右下方向に 4 文字抜き出す例
乱数表の一番端の文字を抜き出した後もさらに文字を抜き出す必要がある場合は、向きを変更して残りの文字を抜き出します。向きの変更は以下のように行います。
- 読み込み時に進んでいた方向が上下左右の場合
- 向きを 180 度変える
- 読み込み時に進んでいた方向が斜めの場合
- 角で向きを変更する場合
- 向きを 180 度変える
- 左右の端で向きを変更する場合
- 左右への向きのみ逆にし、上下への向きはそのままにする
- 上下の端で向きを変更する場合
- 上下への向きのみ逆にし、左右への向きはそのままにする
- 角で向きを変更する場合
これらの向きの変更を図で示すと下図のようになる
![](https://img2020.cnblogs.com/blog/1691646/202008/1691646-20200828105040152-421385169.png)
図:変更する向きの一覧
输入格式
入力は以下の形式で標準入力から与えられる。
(x y W)
(c_{11}c_{12}ldots c_{19})
(c_{21}c_{22}ldots c_{29})
(vdots)
(c_{91}c_{92}ldots c_{99})
- 入力は 10 行ある。
- 1 行目には、抜き出す最初の数字が左から何文字目かを表す整数 (x(1 le x le 9) y(1 le y le 9) W)
- 抜き出す方向 W
'R' 'L' 'U' 'D' 'RU' 'RD' 'LU' 'LD'
'R'
: 右方向'L'
: 左方向'U'
: 上方向'D'
: 下方向'RU'
: 右上に斜め方向'RD'
: 右下に斜め方向'LU'
: 左上に斜め方向'LD'
: 左下に斜め方向
- 抜き出す方向 W
- (29c_{ij}(1 le i le 9, 1 le j le 9))
- i 行目 j 番目の数字は、乱数表の上から i 番目、左から j 番目の数字が (c_{ij}) であることを表す。
- (c_{ij}) は
0
-9
のいずれかである。
输出格式
指定された位置から指定された方向に数字を 4 文字抜き出し、それらの数字を標準出力に 1 行で出力せよ。
なお、最後には改行を出力せよ。
输入输出样例
输入 #1
3 5 R
790319030
091076399
143245946
590051196
398226115
442567154
112705290
716433235
221041645
输出 #1
8226
- 乱数表から抜き出す 4 文字は下図のように右方向に抜き出します。
输入 #2
8 9 LU
206932999
471100777
973172688
108989704
246954192
399039569
944715218
003664867
219006823
输出 #2
2853
- 乱数表から抜き出す 4 文字は下図のように左上方向に抜き出します。
输入 #3
5 7 D
271573743
915078603
102553534
996473623
595593497
573572507
340348994
253066837
643845096
输出 #3
4646
- 下図のように下方向へ 3 文字抜き出した後、向きを上方向に変えて残りの 1 文字を抜き出します。
输入 #4
2 2 LU
729142134
509607882
640003027
215270061
214055727
745319402
777708131
018697986
277156993
输出 #4
0700
- 下図のように左上方向へ 2 文字抜き出した後、向きを右下方向に変えて残りの 2 文字を抜き出します。
输入 #5
8 7 RD
985877833
469488482
218647263
856777094
012249580
845463670
919136580
011130808
874387671
输出 #5
8878
- 下図のように右下方向へ 1 文字抜き出した後、向きを左下方向に変えて残りの文字を抜き出します。
- 3 文字目まで抜き出した後、さらに向きを左上方向に変えて残りの 1 文字を抜き出します。
说明/提示
Time Limit: 2 sec / Memory Limit: 64 MB
我的思路
本题乍看上去很难,其实理解题意之后也就是一个简单的模拟题.
麻烦的是分辨初始方向,然后按方向走,碰壁则换方向。碰到横边换y方向,碰到竖边换x方向。
(这题目也太难复制了:),我觉得把它copy过来排版比解题难多了……)
我的代码(遗憾WA)
#include<cstdio>
#include<cstring>
int x, y;
char w[2], mp[15][15]; //方向与地图
int wn[8][2] = { {0,1}, {0,-1}, {-1,0}, {1,0}, {-1,1}, {1,1}, {-1,-1}, {1,-1} }; //8个方向
char ans[4];
bool inx(int xx){
return 0<=xx && xx<9; //x不在边界
}
bool iny(int yy){
return 0<=yy && yy<9; //y不在边界
}
int main(){
scanf("%d%d", &y, &x); //x:行,y:列
scanf("%s", w);
int len = strlen(w);
//输入密码表
for(int i=0; i<9; i++){
scanf("%s", &mp[i]);
}
//判断初始方向
int d = -1;
if(w[0]=='R') d=0;
else if(w[0]=='L') d=1;
else if(w[0]=='U') d=2;
else if(w[0]=='D') d=3;
if(len==2){
if(d==0){
if(w[1]=='U') d=4;
else d=5;
}
else if(d==1){
if(w[1]=='U') d=6;
else d=7;
}
}
x--;
y--;
ans[0] = mp[x][y];
int cx = wn[d][0];
int cy = wn[d][1];
for(int i=1; i<=3; i++){
if(!inx(x+cx)){
cx = -cx;
}
else if(!iny(y+cy)){
cy = -cy;
}
x += cx;
y += cy;
ans[i] = mp[x][y];
}
for(int i=0; i<4; i++){
printf("%c", ans[i]);
}
printf("
");
return 0;
}
他人AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int x, y;
scanf("%d%d", &x, &y);
x--;
y--;
string w;
cin>>w;//操作
char m[9][9];//密码表
for(int i=0; i<9; i++){
scanf("
");//scanf要读空行QAQ
for(int j=0;j<9;j++)
scanf("%c",&m[i][j]);//读入密码表
}
int dx[8]={1,-1,1,0,0,-1,-1,1};//挪动x
int dy[8]={0,0,-1,-1,1,1,-1,1};//挪动y
string s[8]={"R","L","RU","U","D","LD","LU","RD"};//判断指令
printf("%c",m[y][x]);//第一下不用移动
int ddx,ddy;//移动
for(int i=0;i<8;i++)
if(w==s[i])
ddy=dy[i], ddx=dx[i];//判断移动
for(int i=0;i<3;i++){
if(x+ddx<0||x+ddx>=9) ddx=-ddx;//x越界
if(y+ddy<0||y+ddy>=9) ddy=-ddy;//y越界
x+=ddx;
y+=ddy;//移动
printf("%c",m[y][x]);//输出密码
}
puts("");//万恶的换行
return 0;
}
反思
可以明显看出来两份代码思路一模一样,但是我的为什么会错嘞?
根据提交的细节来看:
./Main.cpp: In function ‘int main()’:
./Main.cpp:23:11: warning: format ‘%s’ expects argument of type ‘char*’, but argument 2 has type ‘char (*)[15]’ [-Wformat=]
23 | scanf("%s", &mp[i]);
| ~^ ~~~~~~
| | |
| | char (*)[15]
| char*
./Main.cpp:17:7: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
17 | scanf("%d%d", &y, &x); //x:行,y:列
| ~~~~~^~~~~~~~~~~~~~~~
./Main.cpp:18:7: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
18 | scanf("%s", w);
| ~~~~~^~~~~~~~~
./Main.cpp:23:8: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
23 | scanf("%s", &mp[i]);
| ~~~~~^~~~~~~~~~~~~~
好的,应该是我的字符串读取问题,毕竟二维字符数组的行指针和string还是有区别的,另外也警示我们细心一些。
不过该同学写的string数组来匹配输入的方向,这种解题办法确实比我好多了。
P1003 铺地毯
题目描述
为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有 nn 张地毯,编号从 11 到 nn。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。
地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。
输入格式
输入共 n+2 行。
第一行,一个整数 n,表示总共有 n 张地毯。
接下来的 n 行中,第 i+1 行表示编号 i 的地毯的信息,包含四个整数 a ,b ,g ,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标 (a, b) 以及地毯在 x 轴和 y 轴方向的长度。
第 n + 2 行包含两个整数 x 和 y,表示所求的地面的点的坐标 (x, y)。
输出格式
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出 -1
。
输入输出样例
输入 #1
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2
输出 #1
3
输入 #2
3
1 0 2 3
0 2 3 3
2 1 3 3
4 5
输出 #2
-1
说明/提示
【样例解释 1】
如下图,1 号地毯用实线表示,2 号地毯用虚线表示,3 号用双实线表示,覆盖点 (2,2) 的最上面一张地毯是 3 号地毯。
我的思路
本题要找铺在最上面的一条毯子,显然从后往前找会更快。
每次铺毯子再看看我们的目标坐标有没有在毯子范围内就行了。
AC代码
#include<cstdio>
int n, x, y;
int ans = -1;
bool in(int x1, int y1, int d1, int d2){ //检测目标坐标是否在毯子范围内
return x1<=x && x<=x1+d1 && y1<=y && y<=y1+d2;
}
int main(){
scanf("%d", &n);
int x0[n], y0[n], dx[n], dy[n];
for(int i=0; i<n; i++){
scanf("%d%d%d%d", &x0[i], &y0[i], &dx[i], &dy[i]);
}
scanf("%d%d", &x, &y);
//开始模拟,从后往前
for(int i=n-1; i>=0; i--){
if(in(x0[i], y0[i], dx[i], dy[i])){
ans = i+1;
break;
}
}
//模拟完毕
printf("%d", ans);
return 0;
}
---2020/8/28---