Week 4 CSP M1 可怕的宇宙射线

题目描述

众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!

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

现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。

样例

Input

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

Output

输出一个数 ans,表示有多少个位置会被降智打击。

样例输入

4
4 2 2 3

样例输出

39

在这里插入图片描述

思路

分裂一共有八个方向,向上、右上、向右、右下、向下、左下、向左、左上,偏移量分别用dx、dy表示
vis[300][300]数组标记该点有没有到达过,初始化为0
a[300][300][30][8]使用一个四维数组用来记录某一个点的状态,坐标为x、y的点在i次向op方向是否进行分裂
首先主要思路是采用DFS,但是朴素的DFS会超时,分裂次数为指数级别,所以要对DFS进行剪枝,判断两次分裂是否相同,即是否在x、y的点在i次向op方向分裂,如果该点曾经进行过分裂,那么两个点的后续分裂过程是完全相同的,此时可以进行记忆性剪枝

总结

刚开始做题的时候想的是分裂是对称的,可以只考虑一边的情况,但是后续的分裂仍然复杂,后来看了其他同学的方法,发现可以对后续的分裂继续进行对称,有多条对称轴,直到分裂回到起始的点。
真真体验到了DFS剪枝对于复杂度优化的作用👍

代码

#include <iostream>
using namespace std;
int sum=0;

int dx[8]={0,1,1,1,0,-1,-1,-1};//偏移量 
int dy[8]={1,1,0,-1,-1,-1,0,1};
int vis[300][300]={0};//判断该点是否到达过
int a[300][300][30][8]={0};//判断某个点的分裂是否进行过,四维分别表示x y坐标 第几次分裂 8个方向 
int num[30]={0};

void dfs(int x,int y,int i,int op,int n) 
{
	if(i==n)//分裂次数完成 
		return;
	if(a[x][y][i][op]==1)//这个点进行分裂过 
		return;
	if(a[x][y][i][op]==0)//这个点的分裂没有进行过
	{
		a[x][y][i][op]=1;
		for(int k=0;k<num[i];k++)
		{
			x=x+dx[op];
			y=y+dy[op];
			if(vis[x][y]==0)//点未到达
			{
				vis[x][y]=1;
				sum++;
			} 
		}
		dfs(x,y,i+1,(op+1)%8,n);//进行下一次分裂 
		dfs(x,y,i+1,(op+7)%8,n);
 	} 	
} 

int main()
{
	int n;
	cin>>n;
//	int a[n];
	for(int i=0;i<n;i++)
	{
		cin>>num[i]; 
	}
	dfs(150,150,0,0,n);
	cout<<sum<<endl;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yySakura

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值