【程序设计思维与实践 CSP-M1 C】可怕的宇宙射线

题目描述:

宇宙射线会在无限的二维平面上传播(可看作一个二维网格图),初始方向默认向上。宇宙射线在发射出一段距离后分裂,向该方向左右45分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂n次,每次分裂后前进ai个单位长度。

输入描述:

输入第一行包含一个正整数n(n<=30)表示宇宙射线会分裂n次
第二行包含n个整数,a1,`a2,…,an,第i个数ai(ai<=5)表示第i次分裂的宇宙射线会在原方向走多少单位长度。

样例输入:

4
4 2 2 3

输出描述:

输出一个数ans,表示宇宙射线走过的单位数。

样例输出:

39

数据点说明:

数据点 n
10% <=10
40% <=20
100% <=30

思路:

难点在于对重复点判断的同时不能有较大的时间复杂度。可建立一个较大的bool数组,表示二位平面,用bool值表示该点是否已经走过。因为ai<=5,n<=30,故数组大小300*300已经够用,这里可以稍微取大一些,采用bfs的思想,将宇宙射线的每一次发射,看作是bfs的每一层扩展,即使用队列保存每一次扩展之后的节点与下一次的发射方向。但是这种暴力bfs的做法明显会超时,因此,我们建立一个五维数组,各维含义分别为x坐标,y坐标,方向,长度、第几次扩展。这样,可以用来标记下一层扩展的点,以记录该点有没有被压入队列,若已经进入队列,再次压入只会将相同的路径再走一遍,因此可以舍弃下一次扩展的重复点,这样便可以大大降低程序的时间复杂度。

反思:

1、之前并未想到使用五位数组,而是使用了四维数组,没有第几次扩展这一维,但在测试时test7出现了WA,才意识到,若没有第五维,前几次扩展的记录会对后面重复点的去除产生影响,即可能后几次要扩展的点与前几次已经扩展的点重复,但他们只是这一步相同,而接下来的扩展可能不同,若因此把这些点作为重复点去除,无疑会使一部分情况丢失,因此这里使用了五维数组,或者也可以在每一次标记下一层扩展之前对四维数组进行写零。
2、因为每一层扩展都需要重新标记,且每一层扩展的点其发射长度相同,故五维数组之中长度那一维有些多余,可以去除。
3、对分裂后方向的判断,曾写过一个冗长的switch语句进行判断,但后来发现每次分裂后方向变化有规律可循,即每次分裂之后方向变为原方向的左右45,若将方向按顺时针逆向记录在一个数组中,则分裂后方向为原方向+1mod8和原方向+7mod8。这样可简化对方向的判断。

代码:

#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
struct Point{
	int x;
	int y;
	Point(int thex,int they)
	{
		x=thex,y=they;
	}
};
bool vis[400][400];
bool note[400][400][8][6][30];
queue<pair<Point,int>> qq;
int dx[]={0,-1,-1,-1,0,1,1,1};
int dy[]={1,1,0,-1,-1,-1,0,1};
int main(int argc, char** argv) {
	memset(vis,false,400*400*sizeof(bool));
	memset(note,false,400*400*8*6*30*sizeof(bool));
	int n;
	cin>>n;
	Point now(199,199);
	vector<int> length(n+1);
	for(int i=0;i<n;i++)
		cin>>length[i];
	int count=0,number=1;
	qq.push({now,0});
	note[now.x][now.y][0][length[0]][0]=true;
	for(int i=0;i<n;i++)
	{
		int num=0;
		for(int j=0;j<number;j++)
		{
			now=qq.front().first;
			int forword=qq.front().second;
			qq.pop();
			for(int k=0;k<length[i];k++)
			{
				now.x+=dx[forword];
				now.y+=dy[forword];
				if(!vis[now.x][now.y])
				{
					vis[now.x][now.y]=true;
					count++;
				}
			}
			if(!note[now.x][now.y][(forword+1)%8][length[i+1]][i])
			{
				note[now.x][now.y][(forword+1)%8][length[i+1]][i]=true;
				qq.push({now,(forword+1)%8});
				num++;
			}
			if(!note[now.x][now.y][(forword+7)%8][length[i+1]][i])
			{
				note[now.x][now.y][(forword+7)%8][length[i+1]][i]=true;
				qq.push({now,(forword+7)%8});
				num++;
			}
		}
		number=num;
	}
	cout<<count<<endl;
	return 0;
}
发布了25 篇原创文章 · 获赞 8 · 访问量 537

猜你喜欢

转载自blog.csdn.net/weixin_44034698/article/details/104873428
今日推荐