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. java中ThreadLocalRandom的使用

    java中ThreadLocalRandom的使用 在java中我们通常会需要使用到java.util.Random来便利的生产随机数.但是Random是线程安全的,如果要在线程环境中的话就有可能产生 ...

  2. Spring5参考指南: BeanWrapper和PropertyEditor

    文章目录 BeanWrapper PropertyEditor BeanWrapper 通常来说一个Bean包含一个默认的无参构造函数,和属性的get,set方法. org.springframewo ...

  3. 我对sessionid的理解

    不知道是不是扯蛋,还是太菜... 看上面的的话毫不关系是吧...自己看过一点 关于 说session id 的 一些文章, 貌似都是一样的....以下内容个人理解, 请大家指正... 我想自己举个例子 ...

  4. 谈谈JavaScript中的变量、指针和引用

    1.变量 我们可能产生这样一个疑问:编程语言中的变量到底是什么意思呢? 事实上,当我们定义了一个变量a时,就是在存储器中指定了一组存储单元,并将这组存储单元命名为a.变量a的值实际上描述的是这组存储单 ...

  5. 【K8S】K8S部署Metrics-Server服务

    写在前面 在新版的K8S中,系统资源的采集均使用Metrics-Server服务,可以通过Metrics-Server服务采集节点和Pod的内存.磁盘.CPU和网络的使用率等信息. 读者可参考< ...

  6. 数据库SQL语言从入门到精通--Part 4--SQL语言中的模式、基本表、视图

    数据库从入门到精通合集(超详细,学习数据库必看) 前言: 使用SQL语言时,要注意SQL语言对大小写并不敏感,一般使用大写.所有符号一定是西文标点符号(虽然是常识,但我还是提一嘴) 1.模式的定义与删 ...

  7. DP背包(一)

    01背包 for(int i=0;i<n;i++) //遍历每一件物品 for(int j=v;j>=wei[i];j--)//遍历背包容量,表示在上一层的基础上,容量为J时,第i件物品装 ...

  8. 【学习笔记:Python-网络编程】Socket 之初见

    Socket 是任何一种计算机网络通讯中最基础的内容.当你在浏览器地址栏中输入一个地址时,你会打开一个套接字,可以说任何网络通讯都是通过 Socket 来完成的. Socket 的 python 官方 ...

  9. 第一行Kotlin系列(三)Intent 向上一页返回数据onActivityResult的使用

    1.MainActivity.kt跳转处理 声明全局的按钮对象 private lateinit var button8: Button 实例化按钮对象 button8 = findViewById( ...

  10. hdu5381 The sum of gcd]莫队算法

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=5381 思路:这个题属于没有修改的区间查询问题,可以用莫队算法来做.首先预处理出每个点以它为起点向左和向右连 ...