1⃣️第一标尺一般是距离,可以在Dijkstra时唯一确定
2⃣️当第二第三标尺不具有最优子结构性质时,即必须要遍历完所有路径后才能确定时,比如本题的minremain和minneed必须要把路径上所有点遍历完才可以确定,此时必须要用Dijkstra+dfs
3⃣️为什么dfs时一定要倒着遍历呢?累加的话正着加和倒着加答案为什么不一样?
根据pre,dfs只能从后找到起始节点,temppath确实正着倒着加无所谓,到dfs只能倒着便利
#include<bits/stdc++.h>
using namespace std;
const int MAXN=510;
const int INF=10000000;
int n,m,cmax,sp,numpath=0,G[MAXN][MAXN],weight[MAXN];
int d[MAXN],minneed=INF,minremain=INF;
bool vis[MAXN]={false};
vector<int> pre[MAXN];
vector<int> temppath,path;
void dijkstra(int s){
fill(d,d+MAXN,INF);
d[s]=0;
for(int i=0;i<=n;i++){
int u=-1,min=INF;
for(int j=0;j<=n;j++){
if(vis[j]==false&&d[j]<min){
u=j;
min=d[i];
}
}
if(u==-1) return;
vis[u]=true;
for(int v=0;v<=n;v++){
if(vis[v]==false&&G[u][v]!=INF){
if(d[u]+G[u][v]<d[v]){
d[v]=d[u]+G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[u]+G[u][v]==d[v]){
pre[v].push_back(u);
}
}
}
}
}
void dfs(int v){
if(v==0){
temppath.push_back(v);
int need=0,remain=0;
for(int i=temppath.size()-1;i>=0;i--){
int id=temppath[i];
if(weight[id]>0)
remain+=weight[id];
else{
if(remain>abs(weight[id])){
remain-=abs(weight[id]);
}
else{
need=need+abs(weight[id])-remain;
remain=0;
}
}
}
if(need<minneed){
minneed=need;
minremain=remain;
path=temppath;
}
else if(need==minneed&&remain<minremain){
minremain=remain;
path=temppath;
}
temppath.pop_back();
return;
}
temppath.push_back(v);
for(int i=0;i<pre[v].size();i++){
dfs(pre[v][i]);
}
temppath.pop_back();
}
int main(){
cin>>cmax>>n>>sp>>m;
int u,v;
fill(G[0],G[0]+MAXN*MAXN,INF);
for(int i=1;i<=n;i++){
cin>>weight[i];
weight[i]-=cmax/2;
}
for(int i=0;i<m;i++){
cin>>u>>v;
cin>>G[u][v];
G[v][u]=G[u][v];
}
dijkstra(0);
dfs(sp);
cout<<minneed<<" ";
for(int i=path.size()-1;i>=0;i--){
cout<<path[i];
if(i!=0)
cout<<"->";
}
cout<<" "<<minremain;
return 0;
}