csp补题—C—可怕的宇宙射线

题目描述:

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

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

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


输入格式:

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

输出格式:

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

sample input:

	4 
	4 2 2 3

sample output:

	39

个人思路:

考虑这个题的实质,2^n型分裂,

  • 暴力的做法:从第一个点开始,把之后分裂的每个点都记下来,然后判断走过的路径长。分析BFS空间复杂度O(2n)DFS时间复杂度为O(2n),这样可以拿40分;
  • 剪枝优化:考虑2的指数型分裂的特性,是对称的!也就是说,知道了a,那么他的对称点a’也就知道了
  • 第一步思考:刚开始是Y轴正向,那么只计算往一侧的分裂点并且关于对称轴(此刻是Y轴)对称过来就OK了。
  • 进一步思考:下一步就是第一步分裂后的子枝,对其进行第一步的操作,发现不对,因为他分裂后的子枝还需要与他的父枝进行对称操作,所以说如果正向操作的话,不是很合理。
  • 逆向操作:先从父枝开始,只按照一个方向分裂(我是一只按照往右分裂),一直到头,期间不要visit路径(具体原因后续)。到头后,开始进行对称操作,以最近的对称轴开始,如果对称后的节点没有visit过的,那么标记visit,并且将他放入一个数组中,用于后面对称轴的对称。
  • WHY?首先,对于对称轴来说是有优先级的,譬如第一个和最后一个对称轴,如果刚开始就关于第一个对称轴对称,那么后面还没有生成的点自然而然会被忽略掉,所以从最后的对称轴开始,因为关于他分裂后的点只有唯一的路径,再后退就OK了。
  • why not 期间 visit:如果在一开始的单一路径时就visit了,那么递归开始后,如果优先级高的轴对称后的点是已经被低于他的对称轴visit了,那么改点就不会加入到数组中,就可能会导致该点关于优先级低的对称轴的对称点的缺失。

代码实现:

#include<iostream>
using namespace std;

int n;
int num = 0;
int a[50];
bool visit[500][500] = { false };
pair<int, int>point[10000];
int sign = -1;//标记每一条对称轴的长度
int rnum = 0;//记录主干线的长度
void DFS(int i, int x, int y, int dx, int dy) {
	if (i >= n)return;
	int x1 = 0, y1 = 0;
	for (int j = 1; j <= a[i]; ++j) {
		x1 = x + dx * j;
		y1 = y + dy * j;
		point[++sign].first = x1;
		point[sign].second = y1;
	}
	rnum = sign;
	if (dx == 1 && dy == 1) {// 1 1
		int sbegin = sign;
		//cout << sign << endl;
		DFS(i + 1, x1, y1, 1, 0);
		//cout << sign << endl;
		for (int s = sign; s >= sbegin; --s) {
			if (visit[x1 - y1 + point[s].second][point[s].first - x1 + y1] == false) {
				visit[x1 - y1 + point[s].second][point[s].first - x1 + y1] = true;
				point[++sign].first = x1 - y1 + point[s].second;
				point[sign].second = point[s].first - x1 + y1;
				num++;
			}
		}
	}
	else if (dx == 1 && dy == 0) {// 1 0
		int sbegin = sign;
		DFS(i + 1, x1, y1, 1, -1);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[point[s].first][2 * y1 - point[s].second] == false) {
				visit[point[s].first][2 * y1 - point[s].second] = true;
				point[++sign].first = point[s].first;
				point[sign].second = 2 * y1 - point[s].second;
				num++;
			}
		}
	}
	else if (dx == 1 && dy == -1) {// 1 -1
		int sbegin = sign;
		DFS(i + 1, x1, y1, 0, -1);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[x1 + y1 - point[s].second][x1 + y1 - point[s].first] == false) {
				visit[x1 + y1 - point[s].second][x1 + y1 - point[s].first] = true;
				point[++sign].first = x1 + y1 - point[s].second;
				point[sign].second = x1 + y1 - point[s].first;
				num++;
			}
		}
	}
	else if (dx == 0 && dy == 1) {// 0 1
		int sbegin = sign;
		DFS(i + 1, x1, y1, 1, 1);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[2 * x1 - point[s].first][point[s].second] == false) {
				visit[2 * x1 - point[s].first][point[s].second] = true;
				point[++sign].first = 2 * x1 - point[s].first;
				point[sign].second = point[s].second;
				num++;
			}
		}
	}
	else if (dx == 0 && dy == -1) {// 0 -1
		int sbegin = sign;
		DFS(i + 1, x1, y1, -1, -1);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[2 * x1 - point[s].first][point[s].second] == false) {
				visit[2 * x1 - point[s].first][point[s].second] = true;
				point[++sign].first = 2 * x1 - point[s].first;
				point[sign].second = point[s].second;
				num++;
			}
		}
	}
	else if (dx == -1 && dy == -1) {// -1 -1
		int sbegin = sign;
		DFS(i + 1, x1, y1, -1, 0);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[point[s].second + x1 - y1][y1 - x1 + point[s].first] == false) {
				visit[point[s].second + x1 - y1][y1 - x1 + point[s].first] = true;
				point[++sign].first = point[s].second + x1 - y1;
				point[sign].second = y1 - x1 + point[s].first;
				num++;
			}
		}
	}
	else if (dx == -1 && dy == 1) {// -1 1
		int sbegin = sign;
		DFS(i + 1, x1, y1, 0, 1);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[x1 + y1 - point[s].second][x1 + y1 - point[s].first] == false) {
				visit[x1 + y1 - point[s].second][x1 + y1 - point[s].first] = true;
				point[++sign].first = x1 + y1 - point[s].second;
				point[sign].second = x1 + y1 - point[s].first;
				num++;
			}
		}
	}
	else if (dx == -1 && dy == 0) {// -1 0
		int sbegin = sign;
		DFS(i + 1, x1, y1, -1, 1);
		for (int s = sign; s >= sbegin; --s) {
			if (visit[point[s].first][2 * y1 - point[s].second] == false) {
				visit[point[s].first][2 * y1 - point[s].second] = true;
				point[++sign].first = point[s].first;
				point[sign].second = 2 * y1 - point[s].second;
				num++;
			}
		}
	}
}
int main() {
	cin >> n;
	for (int p = 0; p < n; ++p) {
		cin >> a[p];
	}
	DFS(0, 250, 250, 0, 1);

	//cout << rnum << endl;
	for (int p = 0; p <= rnum; ++p) {//递归完成后,遍历主干线上的点是否有没遍历的
		if (visit[point[p].first][point[p].second] == false)
			num++;
	}
	cout << num << endl;
	return 0;
}

发布了13 篇原创文章 · 获赞 0 · 访问量 212

猜你喜欢

转载自blog.csdn.net/XianAnn/article/details/105001124
今日推荐