面对这样小的数据范围,为什么要写搜索?于是我来写一个纯粹的模拟。这题不至于评绿吧?

大致的思路就是枚举每一个可能的入射方向,暴力模拟光的传播过程,并在这个过程中记录经过的镜面,进行判断。

我认为这题唯一复杂的地方在于对光的反射方向的处理,有一些题解中用了分类讨论,这明显太复杂了,于是可以使用映射来进行记录,方法如下:

为了方便论述,这里先定义以下的方向编号:

1
2
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};

然后画个图分析一下(画图真的非常重要!):

注:蓝线是镜子,黑线是入射光线,红线是反射光线,数字表示方向编号。

于是用 mp[m][d] 表示方向为 d 的光线经平面镜 m 反射后的方向,顺便把空格方向不变也定义了:

1
2
3
mp['/' ][0]=3;mp['/' ][1]=2;mp['/' ][2]=1;mp['/' ][3]=0;
mp['\\'][0]=1;mp['\\'][1]=0;mp['\\'][2]=3;mp['\\'][3]=2;
mp['.' ][0]=0;mp['.' ][1]=1;mp['.' ][2]=2;mp['.' ][3]=3;

接下来直接模拟,注意用标记数组防止形成死循环,详见代码(不要抄袭啊,建议改变一下方向数组的定义,自己试着重新写一下)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// REMEMBER to replace: cerr -> //cerr                 //
// REMEMBER to use printf/scanf //
// REMEMBER to check the memory limit //
#include<bits/stdc++.h> //
#define int long long //
using namespace std; //
inline int min(int __,int ___){return __<=___?__:___;} //
inline int max(int __,int ___){return __>=___?__:___;} //
#define inf 0x3f3f3f3f3f3f3f3fll //
/////////////////////////////////////////////////////////
int n,m;
char c[300][300];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
map<char,map<int,int> >mp;
struct S{
int x,y,d;
};
map<int,bool>vis;
bool gridvis[300][300];
int sum,tot;
string ans1[40001];
int ans2[40001],ans;
S move(S now){
S ss=now;
ss.x+=dx[mp[c[now.x][now.y]][now.d]];
ss.y+=dy[mp[c[now.x][now.y]][now.d]];
ss.d=mp[c[now.x][now.y]][now.d];
if(c[now.x][now.y]!='.'){
tot+=1-gridvis[now.x][now.y];
gridvis[now.x][now.y]=1;
}
return ss;
}
bool check_ok(S now){
vis.clear();tot=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
gridvis[i][j]=false;
}
}
while(true){
now=move(now);
if(tot==sum)return true;
if(vis[now.x*10000+now.y*10+now.d])return false;
vis[now.x*10000+now.y*10+now.d]=true;
if(now.x>n||now.x<1||now.y>m||now.y<1){
return false;
}
}
return false;
}
void solve(){
ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
if(c[i][j]!='.'){
sum++;
}
}
}
for(int i=1;i<=n;i++){ //W
if(check_ok({i,1,0})){
ans1[++ans]="W",ans2[ans]=i;
}
}
for(int i=1;i<=m;i++){ //N
if(check_ok({1,i,1})){
ans1[++ans]="N",ans2[ans]=i;
}
}
for(int i=1;i<=n;i++){ //E
if(check_ok({i,m,2})){
ans1[++ans]="E",ans2[ans]=i;
}
}
for(int i=1;i<=m;i++){ //S
if(check_ok({n,i,3})){
ans1[++ans]="S",ans2[ans]=i;
}
}
cout<<ans<<endl;
for(int i=1;i<=ans;i++){
cout<<ans1[i]<<ans2[i]<<" ";
}
cout<<endl;
}
signed main(){
#ifdef USE_FILE_IO
freopen("code.in","r",stdin);
freopen("code.out","w",stdout);
#endif
mp['/' ][0]=3;mp['/' ][1]=2;mp['/' ][2]=1;mp['/' ][3]=0;
mp['\\'][0]=1;mp['\\'][1]=0;mp['\\'][2]=3;mp['\\'][3]=2;
mp['.' ][0]=0;mp['.' ][1]=1;mp['.' ][2]=2;mp['.' ][3]=3;
int t;
// cin>>t;
t=1;
while(t--){
solve();
}
return 0;
}