Data Structures and Algorithms7-11——Saving James Bond - Hard Version

我的Data Structures and Algorithms代码仓:https://github.com/617076674/Data-Structures-and-Algorithms

原题链接:https://pintia.cn/problem-sets/16/problems/673

题目描述:

知识点:SPFA算法、深度优先遍历(回溯)

思路:SPFA算法+深度优先遍历(回溯)

定义一个结构体situation来保存坐标,题目表明鳄鱼数量不超过100条,再加上原点坐标(0, 0),因此我们可以用一个大小为101的数组situations来存储各个situation的信息。一个situations数组中的索引就相当于一个situation,也相当于图中的一个点。

这样这个问题就成了从点0开始,求能逃出去的最短路径。注意,这里路径的定义——“The length of a path is the number of jumps that James has to make.”,这里的路径定义为跳跃步数

为避免对浮点数的处理,我们的图graph不保存路径长度,而保存路径长度的平方。

如果从中心岛一步就能逃出该区域,直接输出“1”即可,这种情况需要特殊处理。

用SPFA算法求得(0, 0)到其余各点的最短距离后,就可以从遍历所有能逃出去的鳄鱼的位置,用dfs求出满足题意的最短路径。

期望时间复杂度是O(kM),其中k是一个常数,在很多情况下k不超过2,M是图中的边数,可见这个算法异常高效,并且经常性地优于堆优化的Dijkstra算法。空间复杂度是O(N ^ 2)。

C++代码:

#include<iostream>
#include<vector>
#include<queue>
#include<set>

using namespace std;

struct situation {
	int x, y;
};

int N, D, INF = 1000000000;
situation situations[101];
int graph[101][101];	//无向图graph[i][j]代表situations[i]与situations[j]之间存在的路径长度的平方
int d[101];
int countInq[101];
bool inq[101];
set<int> pre[101];
vector<int> tempPath;
vector<int> path;
int minSteps = INF;	//最少跳跃步数 
int minFirstJump = INF;	//第一步跳的距离最短 

int calculateDistance(situation s1, situation s2);
bool canEscape(situation s);	//从s位置能否逃出
bool spfa(int s);
void dfs(int nowVisit);

int main() {
	situations[0].x = situations[0].y = 0;	//situations[0]是原点,坐标为(0, 0)
	scanf("%d %d", &N, &D);
	for(int i = 1; i <= N; i++) {
		scanf("%d %d", &situations[i].x, &situations[i].y);
	}
	if((D + 7.5) * (D + 7.5) >= 50 * 50) {	//如果一步就能跳出去 
		printf("1\n");
		return 0;
	}
	for(int i = 0; i < N + 1; i++) {
		for(int j = i + 1; j < N + 1; j++) {
			graph[i][j] = graph[j][i] = INF;
		}
	}
	for(int i = 1; i < N + 1; i++) {
		int distance = calculateDistance(situations[0], situations[i]);
		if(distance <= (D + 7.5) * (D + 7.5)) {
			graph[0][i] = graph[i][0] = distance;
		}
	}
	for(int i = 1; i < N + 1; i++) {
		for(int j = i + 1; j < N + 1; j++) {
			int distance = calculateDistance(situations[i], situations[j]);
			if(distance <= D * D) {
				graph[i][j] = graph[j][i] = distance;
			}
		}
	}
	spfa(0);
	for(int i = 1; i < N + 1; i++) {
		if(!canEscape(situations[i])) {
			continue;
		}
		dfs(i);
	}
	printf("%d\n", path.size());
	for(int i = path.size() - 2; i >= 0; i--) {
		printf("%d %d\n", situations[path[i]].x, situations[path[i]].y);
	}
	return 0;
}

int calculateDistance(situation s1, situation s2) {
	return (s1.x - s2.x) * (s1.x - s2.x) + (s1.y - s2.y) * (s1.y - s2.y);
}

bool canEscape(situation s) {
	int len1, len2;
	if(s.y >= 0) {
		len1 = 50 - s.y;
	} else {
		len1 = s.y + 50;
	}
	if(s.x >= 0) {
		len2 = 50 - s.x;
	} else {
		len2 = s.x + 50;
	}
	if(min(len1, len2) <= D) {
		return true;
	} else {
		return false;
	}
}

bool spfa(int s) {
	fill(d, d + N + 1, INF);
	fill(countInq, countInq + N + 1, 0);
	fill(inq, inq + N + 1, false);
	d[s] = 0;
	queue<int> q;
	q.push(s);
	countInq[s]++;
	inq[s] = true;
	while(!q.empty()) {
		int now = q.front();
		q.pop();
		inq[now] = false;
		for(int i = 0; i < N + 1; i++) {
			if(graph[now][i] < INF) {
				if(d[now] + 1 < d[i]) {
					d[i] = d[now] + 1;
					pre[i].clear();
					pre[i].insert(now);
					if(!inq[i]) {
						q.push(i);
						countInq[i]++;
						inq[i] = true;
						if(countInq[i] > N) {
							return false;
						}
					}
				} else if(d[now] + 1 == d[i]) {
					pre[i].insert(now);
					if(!inq[i]) {
						q.push(i);
						countInq[i]++;
						inq[i] = true;
						if(countInq[i] > N) {
							return false;
						}
					}
				}
			}
		}
	}
	return true;
}

void dfs(int nowVisit) {
	tempPath.push_back(nowVisit);
	if(nowVisit == 0) {
		if(tempPath.size() < minSteps) {
			path = tempPath;
			minSteps = tempPath.size();
			minFirstJump = graph[0][tempPath[tempPath.size() - 2]];
		} else if(tempPath.size() == minSteps && graph[0][tempPath[tempPath.size() - 2]] < minFirstJump) {
			path = tempPath;
			minFirstJump = graph[0][tempPath[tempPath.size() - 2]];
		} 
		tempPath.pop_back();
		return;
	}
	for(set<int>::iterator it = pre[nowVisit].begin(); it != pre[nowVisit].end(); it++) {
		dfs(*it);
	}
	tempPath.pop_back();
}

C++解题报告:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值