PAT A1018 Dijkstra+DFS+第三标尺

该博客探讨了一个城市公共自行车系统中如何通过最短路径调整自行车数量,使得各站点达到完美状态的问题。利用Dijkstra算法找到从控制中心到指定问题车站的最短路径,并在此过程中动态调整自行车的携带和补给。博客内容涉及动态规划、图论和运筹学,旨在解决实际操作中的资源配置优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:城市里有一些公共自行车站,每个车站的最大容量为一个偶数 C m a x Cmax Cmax,如果该车站的自行车数量为 C m a x 2 \frac{Cmax}{2} 2Cmax,那么就称该车站处于完美状态。
如果一个车站的容量是满的或者空的,控制中心就要携带或者从路上搜集一定数量的自行车前往该车站,以使问题车站及沿途所有车站处于完美状态。现给出 C m a x Cmax Cmax、车站数目 n n n、问题车展编号 S p S_p Sp、无向边数 M M M以及边权,求一条从控制中心到 S p S_p Sp的最短路径,输出需要携带的自行车数目、路径、需要携带回中心的数目。如果路径有多条,则选择携带最少的;如果仍有多条,则选择带回中心最少的。

注意“调整过程需要在前往问题车站的过程中就调整完毕,返程不调整。

分析:
1.调整的过程是动态的,类似加油问题,而不能单纯的算总和。
英文原文是读不出动态过程的。
2.本题加入了第三标尺,第一标尺是距离,第二标尺是需求need,第三标尺是剩余remain。
注意:第二标尺更新时,第三标尺无条件更新,不要说是 Dijkstra+DFS就忘了这一点。

加油问题的逻辑:
在DFS从终点回溯到起点,计算路径总权值时,设need表示需要从中心带的数目,remain表示当前剩余的可用来补给的数目。

// 递归终点
	if(v == 0) {
		tmpPath.push_back(v);
		int need = 0,remain = 0;

		for(int i = tmpPath.size()-2; i >= 0; --i) {
			int id = tmpPath[i];
			if(weight[id] >= cmax / 2) {
				// 如果超过了一半,可以用来补给
				remain += weight[id] - cmax / 2;
			} else {
				// 当前不够

				if(remain > cmax/2-weight[id]) {
					// 携带的够补给,那么就补给
					remain -=   cmax/2-weight[id];
				} else {
					// 不够,补给剩下的要从 PBMC 带

					need += (cmax/2-weight[id])-remain;
					remain = 0;
				}
			}


		}

		

完整代码:

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
#define INF 0x3fffffff
#define MAXN 550
using namespace std;


int cmax,n,sp,m;
int weight[MAXN];
int G[MAXN][MAXN];

int d[MAXN];
bool vis[MAXN] = {false};
int w[MAXN];
vector<int> pre[MAXN];

void Dijkstra(int s) {

	// 0.初始化
	fill(d,d+MAXN,INF);
	d[0] = 0;

	// n 次循环
	for(int i = 0; i <= n; ++i) {
		// 1. 从 V-S 中取出最近的
		int u = -1,MIN = INF;
		for(int j = 0; j <= n; ++j) {
			if(vis[j] == false && d[j] < MIN) {
				u = j;
				MIN = d[j];
			}
		}

		// 2.加入 S
		if(u == -1)	return ;
		vis[u] = true;

		//3.扩展 u
		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[u]+G[u][v] == d[v]) {
					pre[v].push_back(u);
				}
			}
		}
	}
}

vector<int> tmpPath,Path;
int minRemain = INF,minNeed = INF;
int bestValue;
int flag;			// 0 是找最大值,1 是找最小值 (full)
void DFS(int v) {
	// 递归终点
	if(v == 0) {
		tmpPath.push_back(v);
		int need = 0,remain = 0;

		for(int i = tmpPath.size()-2; i >= 0; --i) {
			int id = tmpPath[i];
			if(weight[id] >= cmax / 2) {
				// 如果超过了一半,可以用来补给
				remain += weight[id] - cmax / 2;
			} else {
				// 当前不够

				if(remain > cmax/2-weight[id]) {
					// 携带的够补给,那么就补给
					remain -=   cmax/2-weight[id];
				} else {
					// 不够,补给剩下的要从 PBMC 带

					need += (cmax/2-weight[id])-remain;
					remain = 0;
				}
			}


		}

		if(need < minNeed) {
			minNeed = need;
			Path = tmpPath;
			minRemain = remain;
		} else if(need == minNeed) {
			if(remain < minRemain) {
				minRemain = remain;
				Path = tmpPath;
			}
		}


		tmpPath.pop_back();
		return ;
	}

	// 递归式,所有可走点 DFS
	tmpPath.push_back(v);
	for(int i = 0; i < pre[v].size(); ++i) {
		DFS(pre[v][i]);
	}
	tmpPath.pop_back();
}

int main() {
	fill(G[0],G[0]+MAXN*MAXN,INF);
	scanf("%d%d%d%d",&cmax,&n,&sp,&m);
	for(int i = 1; i <= n; ++i) {
		scanf("%d",&weight[i]);
	}
	int si,sj,t;
	for(int i = 0; i < m; ++i) {
		scanf("%d%d%d",&si,&sj,&t);
		G[si][sj] = G[sj][si] = t;
	}


	Dijkstra(0);
	DFS(sp);
	int len = Path.size();

	printf("%d ",minNeed);
	printf("0");
	for(int i = len-2; i >= 0; --i) {
		printf("->%d",Path[i]);
	}
	printf(" %d",minRemain);


	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值