1018. Public Bike Management

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.



Figure 1

Figure 1 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(<= 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. The second 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 after one space, output the path in the format: 0->S1->...->Sp.
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



题目大意:每个自行车站容量为cmax,当放置车数为cmax/2时则为完美状态。现在给出cmax,车站数n,出问题的车站sp,m条互相可达的边以及它们的距离,从起点到达sp的路上会沿途调整那些需要调整的车站。此时需要求出:从出发点到问题车站所需距离最短的路线;如果有多条距离相同的路,则选择需要从起点携带车数最少的路;如果还是不唯一,则选择带回车数最少的路线。



主要思想:1. 此题是加权有向图的最短路径问题,很容易想到dijkstra,但是dijkstra无法解决第三点要求,即距离相同、带出车数相同时带回车数最小,带回车数需要在整条路径经过之后才能判断,无法在过程中立即做出选择。

所以需要使用dijkstra+dfs的方法,先找到其中一条最短路径,此时每个点到起点的最短距离都已经获得,然后利用深度优先搜索从终点反向搜索来找出所有存在的最短路径,每一次与当前保存的路径比较,从而找出其中符合要求的最优的那一条。注意反向搜索时只访问那些在其中一条最短路径上的顶点。

//dijkstra + dfs
#include <stdio.h>
#include <limits.h>
#define MAXN 501 int num[MAXN]; //各点的车数
int s[MAXN][MAXN]; //邻接矩阵表示图
int marked[MAXN]; //标记已被放松过的顶点
int distTo[MAXN]; //各点相对于起点的距离
int next[MAXN]; //下一个顶点
int path[MAXN]; //符合要求的最短路径 void relax(int v);
int min();
void dfs(int v);
void cal(int i); int n, c, sp;
int ns, nb;
//带出车的最小辆数 和 带回车的最小辆数
int n_sent = INT_MAX, n_back = INT_MAX; int main(void) {
int m, i, v, w, time;
int count = 0; scanf("%d%d%d%d", &c, &n, &sp, &m);
for (i = 1; i <= n; i++) {
scanf("%d", &num[i]);
}
for (i = 0; i < m; i++) {
scanf("%d%d%d", &v, &w, &time);
s[v][w] = time;
s[w][v] = time;
}
for (i = 1; i <= n; i++)
distTo[i] = INT_MAX; //初始化各顶点到起点的距离
distTo[0] = 0;
while (!marked[sp]) { //当sp已经被放松,则说明最短路径已找到
relax(min());
}
dfs(sp); printf("%d ", n_sent);
for (i = 0; path[i] != sp; i++) {
printf("%d->", path[i]);
}
printf("%d ", sp);
printf("%d\n", n_back); return 0;
} void relax(int v) {
int i, t; marked[v] = 1;
for (i = 0; i <= n; i++) {
t = s[v][i];
if (t == 0 || marked[i]) continue;
if (distTo[i] > distTo[v] + t) {
distTo[i] = distTo[v] + t;
}
}
} void dfs(int v) {
int i, count, t; for (i = 0; i <= n; i++) {
t = s[v][i];
//只访问已被标记过的顶点而且 该点必须是在其中一条最短路径上
if (t == 0 || !marked[i] || (distTo[i] + t != distTo[v])) continue;
next[i] = v;
dfs(i);
}
if (v != 0) return; ns = 0; //需要从起点携带的车数
nb = 0; //当前身上的车数
for (i = next[0]; i != sp; i = next[i]) {
cal(i);
}
cal(sp);
//当前这条最短路径与已经保存的最优解比较,判断是否需要更新最优路径
if (ns < n_sent || (ns == n_sent && nb < n_back)) {
count = 0;
n_sent = ns;
n_back = nb;
for (i = 0; i != sp; i = next[i]) {
path[count++] = i;
}
path[count] = sp;
}
} //计算到达每一个点时 要从起点携带的车数(是一直累加的) 和 当时身上的车数(要带回的车数)
void cal(int i) {
int x; if (num[i] > c/2) //此站车多,从中取出
nb += num[i] - c/2;
else if (num[i] < c/2) { //此站车少,补充放入
x = nb - (c/2 - num[i]);
if (x >= 0)
nb = x;
else { //身上的不够,起点携带数增加
ns += -x;
nb = 0;
}
}
} //找到距离起点最短的点,即下一个需要放松的点
int min() {
int i, min_index;
int min = INT_MAX; for (i = 0; i <= n; i++) {
if (!marked[i] && distTo[i] < min) {
min = distTo[i];
min_index = i;
}
} return min_index;
}

2. 还有一种方法是只用dfs完成,利用回溯使图中只存在一条路线,这种方法不拘束于只找最短路径,而是找出所有从起点到终点的路径,每一次都与当前保存的最优解进行比较,判断是否更新。

//dfs
#include <stdio.h>
#include <limits.h>
#define MAXN 501
int num[MAXN];
int s[MAXN][MAXN];
int marked[MAXN];
int next[MAXN];
int path[MAXN];
int n, c, sp;
int ns, nb, nt;
int n_sent = INT_MAX, n_back = INT_MAX, t_path = INT_MAX;
void cal(int i);
void dfs(int v); int main(void) {
int m, i, j, v, w, time;
int count = 0; scanf("%d%d%d%d", &c, &n, &sp, &m);
for (i = 1; i <= n; i++) {
scanf("%d", &num[i]);
}
for (i = 0; i < m; i++) {
scanf("%d%d%d", &v, &w, &time);
s[v][w] = time;
s[w][v] = time;
}
dfs(0); printf("%d ", n_sent);
for (i = 0; path[i] != sp; i++) {
printf("%d->", path[i]);
}
printf("%d ", sp);
printf("%d\n", n_back); return 0;
} void dfs(int v) {
int i, t, count; marked[v] = 1;
for (i = 0; i <= n; i++) {
if (v == sp) break;
t = s[v][i];
if (t > 0 && !marked[i]) {
next[v] = i;
dfs(i);
}
}
marked[v] = 0; //回溯,取消标记
if (v != sp) return;
nt = 0;
ns = 0;
nb = 0;
for (i = 0; i != sp; i = next[i]) {
nt += s[i][next[i]];
if (i == 0) continue;
cal(i);
}
cal(sp);
if (nt > t_path) return;
if (nt == t_path) {
if (ns < n_sent || (ns == n_sent && nb < n_back)) { }
else return;
}
n_sent = ns;
n_back = nb;
t_path = nt;
for (i = 0, count = 0; i != sp; i = next[i]) {
path[count++] = i;
}
path[count] = sp;
} void cal(int i) {
int x; if (num[i] > c/2)
nb += num[i] - c/2;
else if (num[i] < c/2) {
x = nb - (c/2 - num[i]);
if (x >= 0)
nb = x;
else {
ns += -x;
nb = 0;
}
}
}


PAT-1018 Public Bike Management(dijkstra + dfs)的更多相关文章

  1. PAT 1018 Public Bike Management(Dijkstra 最短路)

    1018. Public Bike Management (30) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...

  2. PAT A1018 Public Bike Management (30 分)——最小路径,溯源,二标尺,DFS

    There is a public bike service in Hangzhou City which provides great convenience to the tourists fro ...

  3. 1018 Public Bike Management (30 分)(图的遍历and最短路径)

    这题不能直接在Dijkstra中写这个第一 标尺和第二标尺的要求 因为这是需要完整路径以后才能计算的  所以写完后可以在遍历 #include<bits/stdc++.h> using n ...

  4. PAT 1018 Public Bike Management[难]

    链接:https://www.nowcoder.com/questionTerminal/4b20ed271e864f06ab77a984e71c090f来源:牛客网PAT 1018  Public ...

  5. 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 ...

  6. PAT 1018. Public Bike Management

    There is a public bike service in Hangzhou City which provides great convenience to the tourists fro ...

  7. 1018 Public Bike Management (30) Dijkstra算法 + DFS

    题目及题解 https://blog.csdn.net/CV_Jason/article/details/81385228 迪杰斯特拉重新认识 两个核心的存储结构: int dis[n]: //记录每 ...

  8. PAT 甲级 1018 Public Bike Management (30 分)(dijstra+dfs,dfs记录路径,做了两天)

    1018 Public Bike Management (30 分)   There is a public bike service in Hangzhou City which provides ...

  9. PAT甲级1018. Public Bike Management

    PAT甲级1018. Public Bike Management 题意: 杭州市有公共自行车服务,为世界各地的游客提供了极大的便利.人们可以在任何一个车站租一辆自行车,并将其送回城市的任何其他车站. ...

随机推荐

  1. spark下dataframe转为rdd格式

    dataframe可以实现很多操作,但是存储到本地的时候,只能存 parquest格式 需要存储源格式,需要转换为rdd类型 将dataframe中的每一行都map成有逗号相连的string,就变为了 ...

  2. Mina Basics 02-基础

    基础 在第1章中,我们简要介绍了Apache MINA.在本章中,我们将了解客户端/服务器体系结构以及有关基于MINA的服务器和客户端的详细信息. 我们还将基于TCP和UDP公开一些非常简单的服务器和 ...

  3. MySQL UDF Dynamic Library Exploit in *nix

    /* } 本文转hackfreer51CTO博客,原文链接:http://blog.51cto.com/pnig0s1992/575448,如需转载请自行联系原作者

  4. POJ 1845-Sumdiv(厉害了这个题)

    Description Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. D ...

  5. 使用Jexus 容器化您的 Blazor 应用程序

    在本文中,我们将介绍如何将 Blazor 应用程序放入Jexus 容器以进行开发和部署.我们将使用 .NET Core  CLI,因此无论平台如何,使用的命令都将是相同的. Blazor 托管模型 B ...

  6. centos7 源码安装goaccess

    1. 使用yum安装在不同服务器上可能失败, 推荐使用源码安装goaccess # 安装依赖 yum install -y ncurses-devel GeoIP-devel.x86_64 tokyo ...

  7. java权限设计思考

    1.粗粒度权限设计与细粒度权限设计             粗粒度(Coarse-graind)        表示类别级,即仅考虑对象的类别(the   type   of   object),不考 ...

  8. 数位dp H - F(x) HDU - 4734

    http://acm.hdu.edu.cn/showproblem.php?pid=4734 一般数位dp表示的是数的性质,这个题目也是一样,但是我们求出来的是一个函数的值,怎么把这个值转化成一类数, ...

  9. 常用linux命令学习记录

    批量替换文件中字符串: sed -i "s/ITSApi/icallApi/g" `grep ITSApi -rl icallbiz` 解释: 将icallbiz目录文件中包涵的I ...

  10. 003_python的str切片,str常用操作方法,for循环,集合,深浅copy

    基础数据类型 基础数据类型,有7种类型,存在即合理. 1.int 整数 主要是做运算的 .比如加减乘除,幂,取余  + - * / ** %... 2.bool布尔值 判断真假以及作为条件变量 3.s ...