可怕的宇宙射线

题意介绍

一条宇宙射线,开始时向上 传播,每经过一段时间,射线就向左右各45度方向裂成两条射线,并继续向分裂方向传播,给出分裂的次数,以及每次走的步数,求出这条射线共经过了多少位置。

题意分析

想到了用递归解决该问题,但是每次分裂之后的方向问题没有想到该怎么简洁的表示出来。想到之前做过的一个迷宫问题,主人公每次可以向上、下、左、右四个方向前进,当时用了两个数组来标记每次往哪个方向前进。代码如下:


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

迷宫问题和这道题其实类似,只不过他不是分裂成两个方向而是旋转一定的角度,这个角度是90度,这道题目将90度换成了45度,意味着又多了一半的选择,表示方向如下:

int X[8] = { 0,1,1,1,0,-1,-1,-1 };
int Y[8] = { 1,1,0,-1,-1,-1,0,1 };

此题开了400×400的数组用来表示每走一步经过点的位置,在递归时,没经过一个点就将该点标记,同时计数共走过多少点。同时,在递归过程中,当遇到交点时,就产生了两个方向,如果一个方向我们已经遍历过了,就没有必要再进行一遍遍历,所以,我们要对已经遍历过的路径加一个标记,防止二次遍历,每一个点除了有他的位置信息外,还有两个信息,就是这个点处在第几次分裂以及该次分裂的哪个方向上,因此,可以创建一个四维数组对每个点在进行标记。递归结束的条件就是该点对应的四维数组值为1或者遍历次数达到上限。

通过代码

#include<iostream>
using namespace std;


bool vis[400][400];
bool flag[400][400][30][8];
int sum;
int ai[30];
int n;

int X[8] = { 0,1,1,1,0,-1,-1,-1 };
int Y[8] = { 1,1,0,-1,-1,-1,0,1 };

void f(int x, int y, int direction, int num) {
	if (flag[x][y][num][direction] == 1 || num > n - 1) return;
	flag[x][y][num][direction] = 1;
	for (int i = 0; i < ai[num]; i++) {
		x += X[direction];
		y += Y[direction];
		if (vis[x][y] == 0) {
			vis[x][y] = 1;
			sum++;
		}
	}
	f(x, y, (direction + 1) % 8, num + 1);
	f(x, y, (direction + 7) % 8, num + 1);

}
int main() {
	
	cin >> n;

	for (int i = 0; i < n; i++) {
		cin >> ai[i];
	}

	int direction = 0;
	int x = 200;
	int y = 200;
	int num = 0;

	f(x, y, direction, num);
	
	
	cout << sum << endl;

}
发布了40 篇原创文章 · 获赞 0 · 访问量 1077

猜你喜欢

转载自blog.csdn.net/weixin_44934885/article/details/104898545
今日推荐