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;
}
posted @ 2024-10-05 16:48  Jerrycyx  阅读(15)  评论(0编辑  收藏  举报