PAT_A1018 Public Bike Management题解

1018 Public Bike Management (30 分)

 
作者: CHEN, Yue
单位: 浙江大学
时间限制: 400 ms
内存限制: 64 MB
代码长度限制: 16 KB
 

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.

The above figure illustrates an example. The stations are represented by vertices and the roads correspond to the edges. The number on an edge is the time taken to reach one end station from another. The number written inside a vertex S is the current number of bikes stored at S. Given that the maximum capacity of each station is 10. To solve the problem at S3​​, we have 2 different shortest paths:

  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​​ (≤), always an even number, is the maximum capacity of each station; N (≤), 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. The second line contains N non-negative numbers Ci​​ (,) 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 after one space, output the path in the format: 0. Finally after another space, output the number of bikes that we must take back to PBMC after 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

不得不说,看完才知道,这就是写个最短路径+符合题目要求的路径嘛,最短路径还不简单dijkstra + heap优化,冲冲冲。
然后:
  卡在了怎么找到符合题目要求的路径上了
其实,一个神奇的pre数组+vector可以完美的解决此类问题,你每次把该节点的头节点更新,如果能使从0到此节点的路径能缩小的,把那个vector清空在把他的头一个插入,如果路径一样的,我们就直接push_back一个就好了,这样你在遍历的时候从要去平衡的节点开始,寻找头节点,这样一个个递归找到0就是一条路径,所以用DFS解决就很好(因为只用一个temppath的vector就能存下每一次的路径,而且切换到另外一个路径的时候不用全删掉重新来)
于是乎就上代码了还有坑!!!:
  1.在结尾output那里特别声明了:如果路径最短且需要带的自行车也最短,那么选取带回来最短的自行车。
  2.在这一路上走走停停但是这条路上的所有车站的车都必须得平衡。
AC代码(借鉴了算法笔记上机训练那本书):
#include <stdio.h>
#include <vector>
#include <queue>
#define scanf_s scanf
using namespace std;
const int INF = 0x3fffffff;
struct Node {
	int id;//节点 
	int value;//某节点到节点的距离 
	Node(int x, int y) {//这样搞我们可以使用Node(x, y)来声明一个临时的Node变量 
		id = x;
		value = y;
	}
	friend bool operator < (Node x, Node y) {//重载<,注意在优先队列中return x.value > y.value 
		return x.value > y.value;
	}
};
int d[505];//i点到0点的最短距离 
int minbring = 0x7ffffff, minhave = 0x7fffffff;//最短要携带的车,最短最后剩余的车 
vector<int> pre[505];//最短距离的前驱节点集合 
vector<int> anspath, temppath;//答案路径,临时路径 
vector<Node> v[505];//邻接表式的存储v[i]所联通的节点 
priority_queue<Node> pq;//优先队列pq 
bool vis[505];//判断该节点是否已经被dijkstra搞完了 
int a[505];//记录每个节点的车 
void findminload()
{
	fill(d, d + 505, INF);//dijkstra的全设为最大 
	d[0] = 0;
	pq.push(Node(0, d[0]));
	while (!pq.empty())
	{
		int z = pq.top().id;//距离0点最小距离的节点 
		pq.pop();
		if (vis[z])//如果这个节点已经搞完了 
			continue;
		vis[z] = true;
		for (int i = 0; i < v[z].size(); i++)
		{
			if (d[z] + v[z][i].value < d[v[z][i].id])
			{
				d[v[z][i].id] = d[z] + v[z][i].value;
				pre[v[z][i].id].clear();//因为之前的前驱在连路径都不能保障最小了,所以全删掉 
				pre[v[z][i].id].push_back(z);//放入新的 
				pq.push(Node(v[z][i].id, d[v[z][i].id]));//更新pq!!!!好多个vector但是别忘了这个 
			}
			else if (d[z] + v[z][i].value == d[v[z][i].id])//相等,说明有多条最短路径 
			{
				pre[v[z][i].id].push_back(z);//前驱节点我都记上 
			}
		}
	}
}
void dfs(int now)
{
	temppath.push_back(now); 
	if (now == 0)//如果找到头了 
	{
		int bring = 0, have = 0;//bring记录本条最短路径所需要带的车,和带走的车 
		for (int i = temppath.size() - 1; i >= 0; i--)//记得我们是递归查找,顺序要反过来 
		{
			have += a[temppath[i]];//现存先加上当前多/少了的车 
			if (have < 0)//如果小于0,说明之前的车不满足题目条件,得开始就多带些车 
			{
				bring -= have;//开始要多带的车(因为have为负数,直接减) 
				have = 0;
			}
		}
		if (bring < minbring)//如果带的车比当前最小还小,更新 
		{
			minbring = bring;//更新最小值 
			minhave = have;//更新带回去的车 
			anspath = temppath;//更新路径 
		}
		else if (bring == minbring && have < minhave)//如果带的车一样多,但是带回去的车少 
		{
			minhave = have;
			anspath = temppath;
		}
		temppath.pop_back();//DFS回溯 (在临时路径中删掉本节点继续遍历) 
		return;
	}
	for (int i = 0; i < pre[now].size(); i++)//如果没到头,就遍历他的前驱节点 
	{
		dfs(pre[now][i]);
	}
	temppath.pop_back();//DFS回溯 
}
int main(void)
{
	int c, n, q, m;
	scanf("%d %d %d %d", &c, &n, &q, &m);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i]);
		a[i] = a[i] - c / 2;//把a[i]处理成如果>0就表示多了a[i]个,<0就表示少了a[i]个的 
	}
	int temp1, temp2, temp3;
	for (int i = 0; i < m; i++)
	{
		scanf("%d %d %d", &temp1, &temp2, &temp3);
		v[temp1].push_back(Node(temp2, temp3));//无向图存两次,A能到B,B也能到A 
		v[temp2].push_back(Node(temp1, temp3));
	}
	findminload();
	dfs(q);
	printf("%d 0", minbring);
	for (int i = anspath.size() - 2; i >= 0; i--)
	{
		printf("->%d", anspath[i]);
	}
	printf(" %d\n", minhave);
	return 0;
}

  



猜你喜欢

转载自www.cnblogs.com/jacobfun/p/11937853.html