1018 Public Bike Management

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题目大意

一个车站里面自行车的数量恰好为c / 2,那么称处于完美状态。如果一个车站容量是满的或者空的,控制中心(处于结点0处)就会携带或者从路上收集一定数量的自行车前往该车站,一路上会让所有的车站沿途都达到完美。现在给出cmax,车站的数量n,问题车站sp,m条边,还有距离,求最短路径。如果最短路径有多个,求能带的最少的自行车数目的那条。如果还是有很多条不同的路,那么就选一条从车站带回的自行车数目最少的作为最终结果。

思路解析

一道最短路径的问题,首先存在多条路径,而且所有路径都要保存下来,所以path必然是一个二维数组。然后沿着path判断minSend和minBack。显然只有Dijkstra是不够的,需要加上深度优先,从每个路径的终点倒着遍历到控制中心,一路上统计back和send。每遍历完一条路径,要把这条路径记录下来,供输出使用。

示例代码

#include<iostream>
#include<vector>
#include<algorithm>
#define INF (~(0x1<<31))
using namespace std;
int c, n, sp, m, minBack = INF, minSend = INF;
int gra[501][501];
vector<vector<int>> path(501, vector<int>());//因为有多条路径,必须使用二维数组存储当前节点之前的多个pre节点
vector<int> tempath, finapath;//临时路径
vector<int> weight(501);//问题站点,角标为车站序列,元素为车站数目,正数表示需要送回的数量,负数表示需要补给的车辆
void dfs(int v) {
	tempath.push_back(v);
	if (v == 0) {//遍历到总部了
				 //从终点往起始点倒着统计
		int back = 0, send = 0;
		for (int i = tempath.size() - 1; i >= 0; i--) {
			int id = tempath[i];
			if (weight[id] > 0) {//表示需要送回
				back += weight[id];
			}
			else {//需要补给
				  //看看能否通过各站点匀一下
				if (back - abs(weight[id]) > 0) {//能匀
					back -= abs(weight[id]);//爽歪歪,直接不用往回送了
				}
				else {
					send += (abs(weight[id]) - back);
					back = 0;//都匀不过来了,更别提往回送了
				}
			}
		}
		if (send < minSend) {//统计最小值
			minSend = send;
			minBack = back;
			finapath = tempath;
		}
		else if (send == minSend && back < minBack) {
			minBack = back;
			finapath = tempath;
		}
		tempath.pop_back();//回溯 给兄弟节点留位置
		return;
	}
	for (int i = 0; i < path[v].size(); i++) {
		dfs(path[v][i]);
	}
	tempath.pop_back();//没有相连的节点了,要退回到上一步
}
int main() {
	scanf("%d%d%d%d", &c, &n, &sp, &m);
	int dist[501];
	fill(gra[0], gra[0] + 501 * 501, INF);
	fill(dist, dist + 501, INF);
	for (int i = 0; i < n; i++) {
		int temp;
		scanf("%d", &temp);
		weight[i + 1] = temp - c / 2;
	}
	for (int i = 0; i < m; i++) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		gra[a][b] = gra[b][a] = c;
	}
	vector<bool> visited(501, false);
	dist[0] = 0;
	for (int i = 0; i <= n; i++) {//不用初始化 上来就干
		int u, min = INF;
		for (int j = 0; j <= n; j++) {
			if (!visited[j] && dist[j] < min) {
				min = dist[j];
				u = j;
			}
		}
		visited[u] = true;
		for (int j = 0; j <= n; j++) {//更新最短路径
			if (!visited[j] && gra[u][j] != INF) {
				if (dist[u] + gra[u][j] < dist[j]) {//找到了新的最短路径
					path[j].clear();//之前储存的所有节点全部作废
					path[j].push_back(u);//新的前驱
					dist[j] = dist[u] + gra[u][j];
				}
				else if (dist[u] + gra[u][j] == dist[j]) {//路径长度相等 此时是多条路径
					path[j].push_back(u);
				}
			}
		}
	}
	dfs(sp);//从最后一个节点开始,个数就是序列
	printf("%d 0", minSend);//多输出一个0
	for (int i = finapath.size() - 2; i >= 0; i--) {
		printf("->%d", finapath[i]);
	}
	printf(" %d", minBack);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值