【PAT-A1018】Public Bike Management(dijkstra + DFS最短路)

本文探讨了在解决特定路径搜索问题时遇到的理解陷阱及优化策略。通过详细解析一道涉及控制中心到目的地最短路径的问题,揭示了在不唯一路径情况下如何选择最优解的方法。文章强调了在DFS和Dijkstra算法结合使用时,正确更新最优值的重要性,并提醒注意题目细节,如顶点数量的实际定义。

【分析】

这题题意不是很清楚,有题目理解上的陷阱,因为题目没有说得很清楚。
主要就是

  • 在题目说明部分,说当最短路不唯一时,选从控制中心带去自行车数最小的那条路。而在输出说明部分,又说不唯一时选从目的地带回自行车最少的路径。这个问题的一种解释就是,因为在题目说明部分并没有说那样的选择方法选出来的就一定保证是唯一的,而在后面那种选择标准后题目说明是唯一的,那么选择标准应该就是先按第一种标准选,再按第二种标准选。

  • 路径上站点的调整应该在前去的路上就完成,回来的时候不再调整。

  • 还有一点在做题时遇到的就是,DFS中更新第二标尺的最优值时,要顺带把第三标尺也更新,这个在普通的单独Dijkstra算法中都会记得,但是在Dijkstra+DFS的做法中就容易忘记。

  • 以及这里有n+1个顶点,不要以为是n个。

【代码】

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 510;
const int INF = (1 << 30) - 1;
int Cmax, n, Sp, m;
int bikeNum[maxn];
int G[maxn][maxn];
bool vis[maxn] = { false };
int d[maxn];
vector<int> pre[maxn], path, tempPath;

void Dijkstra(int s) {
	fill(d, d + maxn, INF);
	d[s] = 0;
	for (int i = 0; i <= n; i++)
	{
		int u = -1, MIN = INF;
		for (int j = 0; j <= n; j++)
		{
			if (vis[j] == false && d[j] < MIN) {
				MIN = d[j];
				u = j;
			}
		}
		if (u == -1) return;
		vis[u] = true;
		for (int v = 0; v <= n; v++)
		{
			if (vis[v] == false && G[u][v] != INF) {
				if (d[v] > d[u] + G[u][v]) {
					d[v] = d[u] + G[u][v];
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if (d[v] == d[u] + G[u][v])
				{
					pre[v].push_back(u);
				}
			}
		}
	}
}
int minSend = INF, minTake = INF;
void DFS(int v, int s) {
	if (s == v) {
		tempPath.push_back(v);

		int send = 0, take = 0, tmp = 0;
		for (int i = tempPath.size() - 1; i >= 0; i--)
		{
			if (i != tempPath.size() - 1) {
				tmp += bikeNum[tempPath[i]];
				if (tmp > 0) {
					
				}
				else
				{
					send += abs(tmp);
					tmp = 0;
				}
			}	
		}
		take = tmp;

		if (minSend > send) {
			minSend = send;
			minTake = take;
			path = tempPath;
		}
		else if (minSend == send) {
			if (minTake > take) {
				minTake = take;
				path = tempPath;
			}
		}

		tempPath.pop_back();
		return;
	}
	tempPath.push_back(v);
	for (int i = 0; i < pre[v].size(); i++)
	{
		DFS(pre[v][i], s);
	}
	tempPath.pop_back();
}
int main() {
	scanf("%d%d%d%d", &Cmax, &n, &Sp, &m);
	fill(G[0], G[0] + maxn * maxn, INF);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &bikeNum[i]);
		bikeNum[i] -= Cmax / 2;
	}
	int c1, c2, t;
	for (int i = 0; i < m; i++)
	{
		scanf("%d%d%d", &c1, &c2, &t);
		G[c1][c2] = G[c2][c1] = t;
	}

	Dijkstra(0);
	DFS(Sp, 0);
	printf("%d ", minSend);
	for (int i = path.size() - 1; i >= 0; i--)
	{
		printf("%d", path[i]);
		if (i > 0) {
			printf("->");
		}
	}
	if (minTake == INF) {
		minTake = 0;
	}
	printf(" %d\n", minTake);
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值