2024牛客暑期多校训练营1 - I. Mirror Maze
题目大意:一个由四种镜面(| - / \
)组成的矩阵,根据镜面的方向反射光线。问坐标 \((x,y)\) 处向某方向射入一束光线后(此光线会直接穿过此位置 \((x,y)\) 的镜面),一共会反射(直接穿过的不算)到多少个不同(一个坐标算一个镜面)的镜面。
总体思路为预处理出每一个坐标向每一个位置发射光线的答案。
处理“不同”的镜面可以直接用 set
记录坐标并去重,最后求 size
。
由于光路可逆,所以光路没有分叉或汇合的情况,故所有的路径一定是环或链。
先考虑链的情况:因为链的尽头一定是边界,所以从四个边界向内发射光线。通过光路可逆将“抵达该坐标时朝向某方向”转化为“离开某坐标时朝向它的反方向”,这样就可以避免递归(会爆栈)或手动堆栈(懒得写)。即在遍历一条光路的时候记录的时它的反向光路的答案。
再考虑环的情况。去除所有的链以后,剩下的还未被访问到的点及方向(注意是某个点的某个方向,不单指这个点)就都在环内。在这些地方和方向再分别发射一条光线进行遍历。当走到已访问过的点时说明走完了一个完整的环。途中记录的环大小(即 set
的大小)就是中途每一个点及方向的答案。
注意记录访问需要单独一个 vst
数组,因为查链的时候可能出现在一条链内但答案是 \(0\) 的情况。
代码如下:
#include<set>
#include<map>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<unordered_map>
using namespace std;
const int N=1005;
int n,m,q;
char str[N][N];
int maze[N][N];
const int rotation[10][10]={
{0,0,0,0,0},
{0,1,2,4,3}, // '|'
{0,2,1,3,4}, // '-'
{0,4,3,2,1}, // '/'
{0,3,4,1,2} // '\'
};
const int trans_x[10]={0,-1,1,0,0};
const int trans_y[10]={0,0,0,-1,1};
const int rev_direction[10]={0,2,1,4,3};
map<string,int> DIR={{"above",1},{"below",2},{"left",3},{"right",4}};
map<char,int> MIR={{'|',1},{'-',2},{'/',3},{'\\',4}};
struct Rain{
int x,y;
int dir; // 1↑ 2↓ 3← 4→ | 进入方向
void step() //先转再走
{
dir=rotation[maze[x][y]][dir];
x+=trans_x[dir],y+=trans_y[dir];
return;
}
bool chg_dir(){return dir!=rotation[maze[x][y]][dir];} //是否改变方向
bool check(){return x>=1&&x<=n && y>=1&&y<=m;}
};
int rev_dir(int dir){return rev_direction[dir];}
int ans[N][N][6];
bool vst[N][N][6];
void Biu(Rain light)
{
set<pair<int,int>> reflect;
while(light.check())
{
ans[light.x][light.y][rev_dir(light.dir)]=reflect.size();
vst[light.x][light.y][rev_dir(light.dir)]=true;
if(light.chg_dir()) reflect.insert({light.x,light.y});
light.step();
}
return;
}
void Prework_chain()
{
for(int i=1;i<=n;i++)
{
Biu({i,1,4});
Biu({i,m,3});
}
for(int i=1;i<=m;i++)
{
Biu({1,i,2});
Biu({n,i,1});
}
return;
}
void Pu(Rain light)
{
set<pair<int,int>> reflect;
vector<Rain> path;
while(!vst[light.x][light.y][rev_dir(light.dir)])
{
vst[light.x][light.y][rev_dir(light.dir)]=true;
if(light.chg_dir()) reflect.insert({light.x,light.y});
path.push_back(light);
light.step();
if(!light.check()) return;
}
for(Rain x:path)
ans[x.x][x.y][rev_dir(x.dir)]=reflect.size();
return;
}
void Prework_cycle()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=4;k++)
if(!vst[i][j][k]) Pu({i,j,rev_dir(k)});
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",str[i]+1);
for(int j=1;j<=m;j++)
maze[i][j]=MIR[str[i][j]];
}
Prework_chain();
Prework_cycle();
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int x,y; scanf("%d%d",&x,&y);
string dir; cin>>dir;
printf("%d\n",ans[x][y][DIR[dir]]);
}
return 0;
}
本文采用 「CC-BY-NC 4.0」 创作共享协议,转载请注明作者及出处,禁止商业使用。
作者:Jerrycyx,原文链接:https://www.cnblogs.com/jerrycyx/p/18447987