1018 Public Bike Management (30分)
分析
求最短路的同时,要求带出的车子最少,再要求带回的车子最少
迪杰斯特拉算法是贪心算法的一种,迪杰斯特拉算法能得出最优解,要求问题满足最优子结构条件。若携带车辆数目与带回车辆数目这两个尺度加到其中的话,满足最优子结构条件,即不能保证当前步骤选择的节点满足路径最短、带出车子最少、带回车子最少的条件时,之后的步骤也满足全局最优的条件
反例如下:
10 4 4 5
6 7 5 0
0 1 1
0 2 1
1 3 1
2 3 1
3 4 1
因此,只能用迪杰斯特拉算法求出最短路径以及对应的各个前驱节点,再用深度优先遍历各个满足最短路径的解,从而得出全局最优解
代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int c, n, s, m, a, b, l, distTo[510], marked[510], bike[510], take_from = 999999999, take_back = 999999999;
vector<int> pre[510], o, oo;
vector<pair<int, int> >g[510];
struct node {
int v, l;
node() {}
node(int vv, int ll) :v(vv), l(ll) {}
bool operator<(node e)const {
return l > e.l;
}
};
void dfs(int i) {
o.push_back(i);
int j = 0;
for (; j < pre[i].size(); ++j)dfs(pre[i][j]);
if (j == 0) {
int ff = 0, bb = 0;
for (int k = o.size() - 2; k >= 0; --k) {
bb += bike[o[k]];
if (bb < 0) {
ff -= bb;
bb = 0;
}
}
if (ff < take_from || (ff == take_from && bb < take_back)) {
oo = o;
take_from = ff;
take_back = bb;
}
}
o.pop_back();
}
int main() {
scanf("%d %d %d %d", &c, &n, &s, &m);
for (int i = 1; i <= n; ++i) {
scanf("%d", &bike[i]);
bike[i] -= c / 2;
}
for (int i = 0; i < m; ++i) {
scanf("%d %d %d", &a, &b, &l);
g[a].push_back(pair<int, int>(b, l));
g[b].push_back(pair<int, int>(a, l));
}
priority_queue<node> q;
q.push(node(0, 0));
fill(distTo, distTo + 510, 999999999);
distTo[0] = 0;
while (!q.empty()) {
int f = q.top().v;
q.pop();
if (f == s)break;
marked[f] = 1;
for (int i = 0; i < g[f].size(); ++i) {
int v = g[f][i].first, l = g[f][i].second;
if (distTo[v] > distTo[f] + l) {
distTo[v] = distTo[f] + l;
pre[v].clear();
pre[v].push_back(f);
q.push(node(v, distTo[v]));
}
else if (distTo[v] == distTo[f] + l)
pre[v].push_back(f);
}
}
dfs(s);
printf("%d 0", take_from);
for (int i = oo.size() - 2; i >= 0; --i)
printf("->%d", oo[i]);
printf(" %d", take_back);
return 0;
}