CSP-M1 C-可怕的宇宙射线

题意

题目描述
众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂n次,每次分裂后会在分裂方向前进a[i]个单位长度。
现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"

输入描述

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

输出描述

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

样例输入

4
4 2 2 3

样例输出

39

数据点说明

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

样例解释

在这里插入图片描述

思路

此题是一个深搜题,但是由于分裂次数最大为30次,为2的30次方,数据量巨大,不可暴力求解,于是采用图论中经常用到的一种方法,标记法,对已经走过的点进行标记,使用一个dir结构来记录每个点的状态(域为一个二维数组,第一维是方向,第二位是第几次分裂(分裂的次数决定了移动的长度)),如果某一点的方向和分裂次数均相同,则可直接返回,因为方向和次数一样表示本次及以后所有的分裂方向和移动的步数全部相同,为减少复杂度可直接返回。

代码

#include<iostream>
#include<string>
#include<cstdio>
#include<cmath>
using namespace std;
int count1 = 0;
struct dir
{
	int a[8][30];
	dir()
	{
		for (int i = 0; i < 8; i++)
		for(int j=0;j<30;j++)
		{
			a[i][j] = 0;
		}
	}
};
void reach(int**, int, int*, int, int, int, int, dir**);
int main()
{
	int n, size = 0;
	cin >> n;
	int* b = new int[n];
	for (int i = 0; i < n; i++)
	{
		cin >> b[i];
		size += b[i];
	}
	int** a = new int* [2 * size + 1];
	dir** a1 = new dir * [2 * size + 1];
	for (int i = 0; i < 2 * size + 1; i++)
	{
		a[i] = new int[2 * size + 1];
		a1[i] = new dir[2 * size + 1];
	}
	for (int i = 0; i < 2 * size + 1; i++)
		for (int j = 0; j < 2 * size + 1; j++)
			a[i][j] = 0;
	int row = size, col = size;
	reach(a, 0, b, n, row, col, 0, a1);
	/*for (int i = 0; i < 2 * size + 1; i++)
	{
		for (int j = 0; j < 2 * size + 1; j++)
			cout << a[i][j] << " ";
		cout << endl;
	}*/
	cout << count1 << endl;
	return 0;
}
void reach(int** a, int num, int b[], int n, int r, int c, int d, dir** a1)//d为方向 向上为0,顺时针标记剩下7个方向 
{
	if (num == n)
		return;
	if (d == 0)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
		{
			if (a[r - i][c] == 0)
			{
				count1++;
				a[r - i][c] = 1;
			}
		}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r - b[num], c, (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r - b[num], c, (d + 8 - 1) % 8, a1);
	}
	else if (d == 1)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
			if (a[r - i][c + i] == 0)
			{
				count1++;
				a[r - i][c + i] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r - b[num], c + b[num], (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r - b[num], c + b[num], (d + 8 - 1) % 8, a1);
	}
	else if (d == 2)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
			if (a[r][c + i] == 0)
			{
				count1++;
				a[r][c + i] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r, c + b[num], (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r, c + b[num], (d + 8 - 1) % 8, a1);
	}
	else if (d == 3)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
			if (a[r + i][c + i] == 0)
			{
				count1++;
				a[r + i][c + i] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r + b[num], c + b[num], (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r + b[num], c + b[num], (d + 8 - 1) % 8, a1);
	}
	else if (d == 4)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
			if (a[r + i][c] == 0)
			{
				count1++;
				a[r + i][c] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r + b[num], c, (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r + b[num], c , (d + 8 - 1) % 8, a1);
	}
	else if (d == 5)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
			if (a[r + i][c - i] == 0)
			{
				count1++;
				a[r + i][c - i] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r + b[num], c - b[num], (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r + b[num], c - b[num], (d + 8 - 1) % 8, a1);
	}
	else if (d == 6)
	{
		if (a1[r][c].a[d][num] == 1)
			return;
		for (int i = 1; i <= b[num]; i++)
			if (a[r][c - i] == 0)
			{
				count1++;
				a[r][c - i] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r , c - b[num], (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r, c - b[num], (d + 8 - 1) % 8, a1);
	}
	else if (d == 7)
	{
	if (a1[r][c].a[d][num] == 1)
		return;
		for (int i =1; i <= b[num]; i++)
			if (a[r - i][c - i] == 0)
			{
				count1++;
				a[r - i][c - i] = 1;
			}
		a1[r][c].a[d][num] = 1;
		reach(a, num + 1, b, n, r - b[num], c - b[num], (d + 8 + 1) % 8, a1);
		reach(a, num + 1, b, n, r - b[num], c - b[num], (d + 8 - 1) % 8, a1);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值