2024牛客多校第一場 - Mirror Maze

Jerrycyx發表於2024-10-05

題目大意:一個由四種鏡面(| - / \)組成的矩陣,根據鏡面的方向反射光線。問座標 \((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;
}

相關文章