这种点权或边权不是简单相加的题,一般来说就必须使用DFS来计算
Dijkstra + DFS
# include <iostream>
# include <vector>
# include <algorithm>
using namespace std;
/* 求最短路径,第二标尺是从起点带最少的单车 */
const int MAXV = 510;
const int INF = 0xffffff;
struct Node{
int v, dis;
};
vector<int> V(510); // 点权
vector<Node> G[510]; // 边权
int dist[510];
int vis[510];
vector<int> pre[510];
int Cmax, N, ed, M;
int st = 0; // 起点是索引0;
void Dijkstra(int s){
fill(dist, end(dist), INF);
fill(vis, end(vis), false);
dist[s] = 0;
for(int i = 0;i < N;++i){
int u = -1;
int MIN = INF;
for(int j = 0; j < N ;++j){
if(vis[j] == false && dist[j] < MIN){
u = j;
MIN = dist[j];
}
}
if(u == -1) return;
vis[u] = true;
for(Node next: G[u]){
int v = next.v ,uvDis = next.dis;
if(vis[v] == false){
if(dist[u] + uvDis < dist[v]){
dist[v] = dist[u] + uvDis;
pre[v].clear();
pre[v].push_back(u);
}
else
if(dist[u] + uvDis == dist[v]){
pre[v].push_back(u);
}
}
}
}
}
int minNeed = INF, minRemain = INF; // 从PBMC出发带走的单车数量,从终点带回PBMC的单车数量
vector<int> path, tempPath;
void DFS(int v){
if(v == st){
tempPath.push_back(st);
int need = 0, remain = 0;
for(int i = tempPath.size() - 1;i >= 0;--i){
int id = tempPath[i];
if(V[id] > 0){ // 当前站点补给多了,不需要补给,需要带走补给,所以remain的多了 ,need不变
remain += V[id]; // 补给数量remain变多了
// need = need; // 不需要补给,所以need不变
}
else{ // 当前站点需要补给,所以remain少了,need多了
if( remain < (-V[id]) ){ // 带来的不够补给
need += (-V[id]) - remain; // 所以need还需要(-V[id]) - remain数量的更多补给
remain = 0; // 把能补给的都补给完了
} else { // 带来的够补给
remain -= (-V[id]); // 所以需要补给(-V[id])数量
// need = need; // 够补给,所以need不变
}
}
}
if(need < minNeed){
minNeed = need;
minRemain = remain;
path = tempPath;
}
else
if(need == minNeed && remain < minRemain){
minRemain = remain;
path = tempPath;
}
tempPath.pop_back();
}
tempPath.push_back(v);
for(int u: pre[v]){
DFS(u);
}
tempPath.pop_back();
}
int main(){
cin >> Cmax >> N >> ed >> M;
for(int i = 1;i <= N;++i){
cin >> V[i];
V[i] -= Cmax/2;
}V[0] = 0;
for(int i = 0;i < M;++i){
int u, v, len;
cin >> u >> v >> len;
G[u].push_back({v, len});
G[v].push_back({u, len});
}
Dijkstra(st);
DFS(ed);
cout << minNeed << " ";
for(int i = path.size() - 1;i >= 0;--i){
cout << path[i];
if(i != 0)
cout << "->";
else
cout << " ";
}
cout << minRemain << endl;
return 0;
}