1018 Public Bike Management (30 分)
解题思路
最短路径问题,除了要求路径最短之外还增加了额外的两个维度,同样最短的路径要求从管理站带去的自行车的量数最小,带去的量数相同时要求带回管理站的自行车的量数最小。解题的思路是Dijstra+DFS。这是解决此类问题的通用套路。
在做这道题的时候我犯了一个非常严重的逻辑错误,导致耽搁了很长时间。设带回去的最小车辆数为mint
,需要带去的最小车辆数为minb
,一条最短路径需要带去和带回的车辆数分别为b
和t
。那么什么时候需要更新mint
呢?当已知一条路径的b
等于minb
的时候,而我却是在b == minb && t < mint
的时候更新,现在想想真是非常低级的错误。犯这个错误部分也是因为我一开始读题不仔细,漏掉了当b == minb
的时候还需要选择t == mint
的线路。
AC代码
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 502;
const int INF = 0x7ffffff;
struct node {
int id;
int t;
node(){}
node(int _id, int _t): id(_id), t(_t) {}
};
int c, n, m, sp, d[maxn];
vector<int> cap, pre[maxn], path, tempPath;
vector<node> adj[maxn];
bool vis[maxn] = {false};
void dijstra() {
fill(d, d + maxn, INF);
d[0] = 0;
for (int i = 0; i <= n; ++i) {
int u = -1, min_d = INF;
for (int j = 0; j <= n; ++j) {
if (vis[j] == false && d[j] < min_d) {
min_d = d[j];
u = j;
}
}
if (u == -1) return;
vis[u] = true;
for (int i = 0; i < adj[u].size(); ++i) {
int v = adj[u][i].id;
if (vis[v] == false) {
if (d[u] + adj[u][i].t < d[v]) {
d[v] = d[u] + adj[u][i].t;
pre[v].clear();
pre[v].push_back(u);
}
else if (d[u] + adj[u][i].t == d[v]) {
pre[v].push_back(u);
}
}
}
}
}
int t, b, minb = INF, mint = INF; // t是带回,b是带去
void DFS(int s) {
if (s == 0) {
tempPath.push_back(s);
t = 0, b = 0;
for (int i = tempPath.size() - 2; i >= 0; --i) {
int v = cap[tempPath[i]] - c/2;
if (v >= 0) {
t += v;
} else {
if (t >= -v)
t += v;
else {
b -= v + t;
t = 0;
}
}
}
if (b < minb) { // 此时需要更新mint
minb = b;
mint = t;
path = tempPath;
} else if (b == minb && t < mint) {
mint = t;
path = tempPath;
}
tempPath.pop_back();
}
tempPath.push_back(s);
for (int i = 0; i < pre[s].size(); ++i) {
DFS(pre[s][i]);
}
tempPath.pop_back();
}
int main() {
scanf("%d%d%d%d", &c, &n, &sp, &m);
cap.resize(n + 1);
for (int i = 1; i <= n; ++i) {
scanf("%d", &cap[i]);
}
for (int i = 0; i < m; ++i) {
int a, b, time;
scanf("%d %d %d", &a, &b, &time);
adj[a].push_back(node(b, time));
adj[b].push_back(node(a, time));
}
dijstra();
DFS(sp);
printf("%d ", minb);
for (int i = path.size() - 1; i >= 0; --i) {
printf("%d%s", path[i], i != 0? "->" : " ");
}
printf("%d\n", mint);
return 0;
}