题目:click me~
题意:
城市公共自行车可在任意站点借还车,每个站点最佳状态是停一半的自行车。管理员在站点0,只要有problem station需要,管理员就要走最短路径 去调整problem station 以及最短路上的站点到最佳状态。
1.若是有几条相同长度的路径,则取需要从站点0带出自行车最少数的那条路。
2.满足1,若是需要自行车数仍然相同,则取要带回站点0自行车最少数的那条路。
输出:需要自行车数 最短路径 带回自行车数
解题思路:
1.用dijsktra算法计算出从点0出发到任意点的最短路,并且记录路径。记录路径的方法:n个顶点各自开一个vector,用来记录前驱节点(一个节点可能有多个前驱,因此处理长度相同的多条路径要用dfs)。
2.求出最短路后,用dfs遍历刚才记录的最短路径。求出minNeed及minBack。
温故:
Dijsktra算法(求正权图中的最短路)
- 算法步骤:
1.将点集v分成两个集合A和B,A中点表示已经求得源点到其的最短路,B中表示待求。(这里我用visit[]来写,true表示在A中,false表示还在B中)
2.每次将点加入A中都要维护数组dis[](表示源点到各点的最短路长度)
3.每次从B中挑选一个到达A中的点边权最小的点。
4.不断加入A,直到B为空。
- 算法代码:
dis[0] = 0; for (int i = 0;i <= n;i++) { int u = -1, minn = inf; for (int j = 0;j <= n;j++) { if (visit[j] == false && dis[j] < minn) { u = j; minn = dis[j]; } } if (u == -1)break;//所有点都visit了,退出循环 visit[u] = true; for (int v = 0;v <= n;v++) { if (visit[v] == false && e[u][v] != inf) { if (dis[v] > dis[u] + e[u][v]) { dis[v] = dis[u] + e[u][v]; pre[v].clear(); pre[v].push_back(u); } else if (dis[v] == dis[u] + e[u][v]) { pre[v].push_back(u); } } } }
code:
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
using namespace std;
const int inf = 99999999;
int cmax, n, sp, m;
int minNeed = inf, minBack = inf;
int e[510][510], dis[510], weight[510];
bool visit[510];
vector<int> pre[510], path, temppath;
void dfs(int v) {
temppath.push_back(v);
if (v == 0) {
int need = 0, back = 0;
for (int i = temppath.size() - 1;i >= 0;i--) {
int id = temppath[i];
if (weight[id] > 0) {
back += weight[id];
}
else {
if (back > (0 - weight[id])) {
back += weight[id];
}
else {
need += (0 - weight[id]) - back;
back = 0;
}
}
}
if (need < minNeed) {
minNeed = need;
minBack = back;
path = temppath;
}
else if (need == minNeed && back < minBack) {
minBack = back;
path = temppath;
}
temppath.pop_back();//删除vector中最后一个元素
return;
}
for (int i = 0;i < pre[v].size();i++)
dfs(pre[v][i]);
temppath.pop_back();
}
int main() {
fill(e[0], e[0] + 510 * 510, inf);
fill(dis, dis + 510, inf);
scanf("%d%d%d%d", &cmax, &n, &sp, &m);
for (int i = 1;i <= n;i++) {
scanf("%d", &weight[i]);
weight[i] = weight[i] - cmax / 2;
}
for (int i = 0;i < m;i++) {
int a, b;
scanf("%d%d", &a, &b);
scanf("%d", &e[a][b]);
e[b][a] = e[a][b];
}
dis[0] = 0;
for (int i = 0;i <= n;i++) {
int u = -1, minn = inf;
for (int j = 0;j <= n;j++) {
if (visit[j] == false && dis[j] < minn) {
u = j;
minn = dis[j];
}
}
if (u == -1)break;//所有点都visit了,退出循环
visit[u] = true;
for (int v = 0;v <= n;v++) {
if (visit[v] == false && e[u][v] != inf) {
if (dis[v] > dis[u] + e[u][v]) {
dis[v] = dis[u] + e[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (dis[v] == dis[u] + e[u][v]) {
pre[v].push_back(u);
}
}
}
}
dfs(sp);
printf("%d 0", minNeed);
for (int i = path.size() - 2;i >= 0;i--)
printf("->%d", path[i]);
printf(" %d", minBack);
return 0;
}