[PAT-A 1018]Public Bike Management

在这里插入图片描述

考察最短路径 Dijkstra算法

题目大意:
某城市中有一些公共自行车站,每个自行车站的最大容量都是一个偶数Cmax,如果一个车站中的自行车数量恰好为Cmax/2,则称该车站为完美车站.
如果一个车站是满的或者空的,则控制中心(PBMC)(起点)会携带从路上收集的一定数量的自行车前往该车站,使问题车站及沿途所有车站都达到完美状态
给出Cmax,车站数目N,问题车站编号sp,无向边数M,边权
求PBMC到问题车站Sp的最短路径,输出需要从PBMC携带的自行车数目,最短路径,到达问题车站后需要带回的自行车数目,如果路径有多条,则选择最后从问题车站带回自行车数目最少的

**思路:考虑Dijkstra+DFS方法[算法笔记]最短路径 Dijkstra算法

第一标尺即求最短路径
求第二标尺:
将每个点的点权都减去(Cmax/2),用正负来判断当前车站是否需要补给,或需要带走的车辆数
定义属性Need:从PBMC到当前车站必须携带的自行车数目,Remain:到达当前车站是手上多余的自行车数目

		//计算最短路径标尺
		int need = 0, remain = 0;
		for (int i = tempPath.size() - 1; i >= 0; i--) {
			int id = tempPath[i];
			if (weight[id] > 0) {
				//如果当前节点点权为正,说明需要收走自行车,收走数量为点权值
				remain += weight[id];
			}
			else {
				//如果点权为负,则从前面收走的remain中向该节点投放自行车
				if (remain > abs(weight[id]))remain -= abs(weight[id]);
				else {
					//如果不够投放,需要从PBMC携带
					need += abs(weight[id]) - remain;
					remain = 0;//当前持有的自行车全部用来补给
				}
			}
		}
		if (need < minNeed) {//最短路径相同,选择需要从PBMC带的最少的情况
			minNeed = need;
			minRemain = remain;
			path = tempPath;
		}
		else if (need == minNeed && remain < minRemain) {//need还相同,选择remain少的情况
			minRemain = remain;
			path = tempPath;
		}

AC代码:

//1018 Public Bike Management(30 分)
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXV = 510;
const int INF = 1000000000;
int n, m, Cmax, Sp, numPath = 0, G[MAXV][MAXV], weight[MAXV];
int d[MAXV], minNeed = INF, minRemain = INF;//minNeed记录最少携带的数目,minRemain记录最少带回的数目
bool vis[MAXV] = { false };
vector<int>pre[MAXV];
vector<int>tempPath, path;
void Dijkstra(int s) {
	fill(d, d + MAXV, 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) {
				u = j;
				MIN = d[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[u] + G[u][v] < d[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);
			}
		}
	}
}
void DFS(int v) {
	if (v == 0) {
		tempPath.push_back(v);
		//计算最短路径标尺
		int need = 0, remain = 0;
		for (int i = tempPath.size() - 1; i >= 0; i--) {
			int id = tempPath[i];
			if (weight[id] > 0) {
				//如果当前节点点权为正,说明需要收走自行车,收走数量为点权值
				remain += weight[id];
			}
			else {
				//如果点权为负,则从前面收走的remain中向该节点投放自行车
				if (remain > abs(weight[id]))remain -= abs(weight[id]);
				else {
					//如果不够投放,需要从PBMC携带
					need += abs(weight[id]) - remain;
					remain = 0;//当前持有的自行车全部用来补给
				}
			}
		}
		if (need < minNeed) {//最短路径相同,选择需要从PBMC带的最少的情况
			minNeed = need;
			minRemain = remain;
			path = tempPath;
		}
		else if (need == minNeed && remain < minRemain) {//need还相同,选择remain少的情况
			minRemain = remain;
			path = tempPath;
		}
		tempPath.pop_back();
		return;
	}
	tempPath.push_back(v);
	for (int i = 0; i < pre[v].size(); i++) {
		DFS(pre[v][i]);
	}
	tempPath.pop_back();
}
int main() {
	(void)scanf("%d %d %d %d", &Cmax, &n, &Sp, &m);
	int u, v;
	fill(G[0], G[0] + MAXV * MAXV, INF);
	for (int i = 1; i <= n; i++) {
		(void)scanf("%d", &weight[i]);
		weight[i] -= Cmax / 2;//点权减去容量的一半,计算距离prefect还差多少
	}
	for (int i = 0; i < m; i++) {
		(void)scanf("%d %d", &u, &v);
		(void)scanf("%d", &G[u][v]);
		G[v][u] = G[u][v];
	}
	Dijkstra(0);
	DFS(Sp);
	printf("%d ", minNeed);
	for (int i = path.size() - 1; i >= 0; i--) {
		//路径的顺序是倒序存放的
		printf("%d", path[i]);
		if (i > 0)printf("->");
	}
	printf(" %d", minRemain);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值