PAT Advanced 1018 Public Bike Management (30) [Dijkstra算法 + DFS]

题目

There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world. One may rent a bike at any station and return it to any other stations in the city.
The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.
When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.

  1. PBMC -> S1 -> S3. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S1 and then take 5 bikes to S3, so that both stations will be in perfect conditions.
  2. PBMC -> S2 -> S3. This path requires the same time as path 1, but only 3 bikes sent from PBMC and hence is the one that will be chosen.

Input Specification:
Each input file contains one test case. For each case, the first line contains 4 numbers: Cmax (<= 100), always an even number, is the maximum capacity of each station; N (<= 500), the total number of stations; Sp, the index of the problem station (the stations are numbered from 1 to N, and PBMC is represented by the vertex 0); and M, the number of roads. Thesecond line contains N non-negative numbers Ci (i=1,…N) where each Ci is the current number of bikes at Si respectively. Then M lines follow, each contains 3 numbers: Si, Sj, and Tij which describe the time Tij taken to move betwen stations Si and Sj. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print your results in one line. First output the number of bikes that PBMC must send. Then afer one space, output the path in the format: 0->S1->…->Sp. Finally afer another space, output the number of bikes that we must take back to PBMC afer the condition of Sp is adjusted to perfect. Note that if such a path is not unique, output the one that requires minimum number of bikes that we must take back to PBMC. The judge’s data guarantee that such a path is unique.
Sample Input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
Sample Output:
3 0->2->3 0

题意

广州公共自行车服务为来自世界各地的旅客提供了很大的便利,从城市中任意站借出自行车后可以在任意站归还
公共自行车管理中心PBMC实时监控城市中每个公共自行车租聘站的容量,若一个站容量刚好半满则该站达到理想状态,如果一个站满或者空,PBMC将收集或者发送自行车去调整该站到理想状态,在去往该问题站的路径上经过的所有站都将被调整为理想状态
当一个站出现问题后,PBMC将选择最短路径到达该问题站,如果最短路径超过一个,则选择发送自行车最少的路径,如果仍然有多条满足条件的路径路径,取从PBMC带回自行车最少的最短路径

题目分析

已知网图顶点数,点权,边权,顶点理想状态定义为点权为最大点权一半,需要走最短路径(边权和最小)将指定顶点的点权调整为理想状态,并将沿途所有顶点点权都调整为最大点权一半。
求满足条件最短路径,若有多个最短路径,取能将路径上所有顶点点权调整为理想状态需要携带的自行车数最少,若仍然有多个满足条件的最短路径,取路径所有顶点调整完毕后需从问题顶点带回的自行车数最少的最短路径

注意:
本题中的多条满足条件最短路径进行筛选时,统计路径上需携带自行车数minNeed最少和返回需携带自行车数minRemain最少时,不能只使用Dijskstra+简单累加思想,因为minNeed和minRemain在路径上的传递不满足最优子结构

测试数据如下:
Smaple2 Input:
10 4 4 5
4 8 9 0
0 1 1
1 2 1
1 3 2
2 3 1
3 4 1
Sample2 Output:
1 0->1->2->3->4 2

解题思路

  1. 存储图
  • 邻接矩阵存储边和边权,int数组存储点权
  • 邻接表存储边和边权,int数组存储点权
  • 结构体邻接表存储边和边权,int数组存储点权
  1. 求单源带权最短路径
    Dijkstra算法:核心为两个整型数组dist[maxn]和path[maxn],每次收集一个顶点v到最短路径中,并判断该顶点是否影响到其他顶点路径边权和,并修改其边权和dist[i]为最小值,修改path[i]为v
    注:必须记录所有最短路径,以便后续步骤进行路径筛选

  2. 路径筛选
    DFS算法:遍历所有最短路径,并挑选出发送自行车最少且带回自行车最少的路径

易错点

本题筛选路径时,若考虑为路径上自行车数的简单加减,会出错(有两个测试点不通过,得分25)

Code

Code 01

#include <iostream>
#include <vector>
#include <stack>
using namespace std;
const int INF=9999999;
const int maxn=510;
int n,cm,sp,vw[maxn],gw[maxn][maxn],dist[maxn],path[maxn],col[maxn];
int minNeed=INF,minRemain=INF;
vector<int> pre[maxn],temp,minp; //统计所有最短路径-逆序
int dmin() {
	int min=INF,mini=-1;
	for(int i=0; i<=n; i++) {
		if(col[i]==0 && min>dist[i]) {
			min=dist[i];
			mini=i;
		}
	}
	return mini;
}
void dijkstra(int c) {
	// 初始化
	fill(dist,dist+n+1,INF);
	fill(path,path+n+1,-1);
	dist[0]=0;
	// 取最小值
	for(int j=0; j<=n; j++) {
		int min=dmin();
		col[min]=1;
		if(min==sp)break; //已找到终点 最短路径
		for(int i=0; i<=n; i++) {
			if(gw[min][i]==0||col[i]==1)continue;
			if(dist[min]+gw[min][i]<dist[i]) {
				dist[i]=dist[min]+gw[min][i];
				path[i]=min;
				pre[i].clear();
				pre[i].push_back(min);
			} else if(dist[min]+gw[min][i]==dist[i]) {
				pre[i].push_back(min);
			}
		}
	}
}
void dfs(int e) {
	if(e==0) {
		int need=0,remain=0;
		for(int i=temp.size()-1; i>=0; i--) {
			int id=temp[i];
			if(vw[id]>0) {
				remain+=vw[id];
			}else{
				if(remain>abs(vw[id])){
					remain-=abs(vw[id]);
				}else{
					need+=abs(vw[id])-remain;
					remain=0;
				}
			}
		}
		if(need<minNeed) { 
			minp=temp;
			minNeed=need;
			minRemain=remain;
		} else if(need==minNeed&&remain<minRemain) {
			minp=temp;
			minRemain=remain;
		}
		return;
	}
	temp.push_back(e);
	for(int i=0; i<pre[e].size(); i++) {
		dfs(pre[e][i]);
	}
	temp.pop_back();
}
int main(int argc,char * argv[]) {
	int m,a,b;
	scanf("%d %d %d %d",&cm,&n,&sp,&m);
	for(int i=1; i<=n; i++){
		scanf("%d",&vw[i]);
		vw[i]-=(cm>>1);
	}
	for(int i=0; i<m; i++) {
		scanf("%d %d",&a,&b);
		scanf("%d",&gw[a][b]);
		gw[b][a]=gw[a][b];
	}
	dijkstra(0);
	dfs(sp);

	printf("%d ",minNeed);
	printf("0");
	for(int i=minp.size()-1; i>=0; i--) {
		printf("->%d",minp[i]);
	}
	printf(" %d",minRemain);
	return 0;
}

原文地址:https://www.cnblogs.com/houzm/p/12366989.html