题意
一个宇宙射线,每一次能够往发射的方向辐射ai个单位长度,然后进行分裂,分裂的方向为发射的方向 左右45°,然后再进行沿着分裂方向辐射a1个长度, 详细请看样例解析图,计算辐射的区域个数
样例输入
4(分裂次数)
4 2 2 3 (每次分裂辐射的长度)
样例输出
39 (区域个数)
样例解释图
思路
- 此题开始想过dfs进行求解,思维格式化,不会弄坐标,然后就不太会做,借鉴了某大佬的博客,茅塞顿开
- 首先就是设立起始坐标,这个很重要,按照题目的数据范围,最多辐射150个长度,所以可以设为(300,300),然后左右上下都不会为负;
- 进行深度搜索,从题目分析有八个方向进行分裂,所以设置偏移量dx,dy进行方向的控制,每一个有八个方向。
- 设置四维数组,前两维是坐标,第三维是第几次分裂,第四维是方向,第三维是为了区别不同分裂次数分裂同一个点,第四维是为了区别同一分裂次数分裂同一个点。初始四维数组为false,分裂之后设置为true;
- 创建一个二维数组,对每一个没有访问的点标记true,然后结果+1;在分裂方向上循环从近到远进行标记辐射线路,循环的长度为每一次分裂的长度。
- 刚开始先进行右侧的搜索,然后进行左侧的搜索,左侧和右侧的区别就是dx偏移量相反。
- 总共具有8个方向,通过循环求余的方法,循环八个方向进行搜索
总结
- 做的时候实在不会做,只知道应该是dfs或者bfs,然后坐标不会设立,便得了0分。
- 去看了某大佬的博客思路,发现了解题思路,思路逐渐明确(感谢大佬),之前思维格式化,以为坐标就是定的,但是在解题中,只需要确定一个初始点,通过偏移量进行相邻位置的探索即可。
- 不管是深度搜索还是广度搜索,相邻位置的整理非常重要,对于这种有多方向,带坐标的,通过dx,dy偏移量实现
代码
#include<iostream>
#include<queue>
using namespace std;
int N;//分裂次数
int N_num = 0;//实时分裂次数
int sum = 0;//被辐射的结点
int dx[] = { 0,1,1,1,0,-1,-1,-1 }; //射线分裂的八个方向,右侧方向
int dy[] = { 1,1,0,-1,-1,-1,0,1 };
int displace[30] = { 0 };//射线分裂的长度
bool split[600][600][30][8];//标记是否被分裂
bool vis[600][600];//标记是否被访问
void dfs_search(int x, int y, int direct, int N_num)
{
//设置dfs的边界
if (N_num ==N)
return;
if (split[x][y][N_num][direct] == false) //此中N_num 为了防止不同次的分裂会到一个点,此中的direct为了防止同次分裂为同一个点
{
split[x][y][N_num][direct] = true;
//下一个结点的增幅
int x1 = dx[direct ];
int y1 = dy[direct ];
//开始点的分裂辐射
for (int i = 1; i <=displace[N_num]; i++) {
if (!vis[x + x1 * i][y + y1 * i]) {
vis[x + x1 * i][y + y1 * i] = true;
sum++;
}
}
int a = x + x1 * displace[N_num]; //下一个应该访问的点x坐标
int b = y + y1 * displace[N_num];
int b_direct = (direct + 1)%8; //右侧
dfs_search(a, b, b_direct, N_num+1); //右侧分裂
b_direct = (direct + 7)%8; //左侧
dfs_search(a, b, b_direct, N_num+1); //左侧分裂
}
}
int main()
{
cin >> N;
for (int i = 0; i < N; i++)
cin >> displace[i];
dfs_search(300, 300, 0,0);//此处300,300为起点,恰好是个对称中心,(此处借鉴大佬的想法)
cout << sum << endl;
return 0;
}