朴素dijkstra + DFS
#include <bits/stdc++.h>
using namespace std;
const int N = 105, inf = 0x3f3f3f3;
int g[N][N], w[N], d[N];
int Cmax, n, m, Sp, bringin = inf, takeback = inf;
bool st[N];
vector<int> pre[N], path, tmp;
void dijkstra(){
memset(d, 0x3f, sizeof d);
d[0] = 0;
while(true){
int v = -1;
for(int i = 0; i <= n; i++){
if(!st[i] && (v == -1 ||d[i] < d[v]) ){
v = i;
}
}
if(v == -1) break;
st[v] = true;
//cout << v << endl;
for(int i = 1; i <= n; i++){
//printf("%d %d %d\n", d[i], g[v][i], d[v]);
if(d[i] > g[v][i] + d[v]){
d[i] = g[v][i] + d[v];
pre[i].clear();
pre[i].push_back(v);
//printf("%d --> %d\n", i, v);
}
else if(d[i] == g[v][i] + d[v]){
//printf("%d --> %d\n", i, v);
pre[i].push_back(v);
}
}
}
return ;
}
void dfs(int x){
//cout << x << endl;
if(x == 0){
tmp.push_back(x);
int need = 0, have = 0;
for(int i = tmp.size()-1; i >= 0; i --){
int j = tmp[i];
if(w[j] > 0){
have += w[j];
}else{
if(have > -w[j]){
have += w[j];
}
else{
need += -w[j] - have;
have = 0;
}
}
}
if(need < bringin){
takeback = have;
bringin = need;
path = tmp;
}
else if(need == bringin && have < takeback){
takeback = have;
path = tmp;
}
tmp.pop_back();
return ;
}
tmp.push_back(x);
//printf("push %d\n", x);
//遍历每一个前驱,通过tmp记录下来
for(int i = 0; i < pre[x].size(); i ++){
int j = pre[x][i];
dfs(j);
}
//回溯时恢复现场
//printf("pop %d\n", tmp.back());
tmp.pop_back();
}
int main(){
cin >> Cmax >> n >> Sp >> m;
for(int i = 1; i <= n; i++) {
scanf("%d", &w[i]);
w[i] -= Cmax / 2;
}
for(int i = 0; i <= n; i ++){
for(int j = 0; j <= n; j++){
g[i][j] = inf;
}
}
for(int i=0; i < m; i++){
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
g[a][b] = g[b][a] = c;
}
dijkstra();
dfs(Sp);
printf("%d ", bringin);
for(int i = path.size() - 1; i >= 0; i --) {
printf("%d", path[i]);
if(i != 0) printf("->");
else printf(" ");
}
printf("%d", takeback);
return 0;
}
写出的bug
1、本题不能直接用dijkstra算出bringin和takeback。需要用pre来记录每个点的所有前驱,在dijkstra完成后再一一对比选出最优解。
2、dfs在回溯时要注意回复现场,如tmp的恢复。
3、创建图时,不要将自己到自己初始化为0,否则在if(d[i] == g[v][i] + d[v])的判断中,每个节点会将自己加入自己的前驱集合。