A1030
堆优化dijkstra + dfs
教训
这种需要考虑边上一些属性来在最短路中选最优解的题目不宜使用邻接表来存储图,否则在记录每个点的前驱时,还需要存入相应的边,代码写的很难看。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = 5e5+10, inf = 1e9;
int h[N], e[M], ne[M], w[M], cost[M], idx, d[N];
bool st[N];
typedef pair<int, int> PII;
priority_queue<PII, vector<PII>, greater<PII> > heap;
//first存放节点,second存放边
vector<PII> pre[N], path, tmp;
int n, m, mincost = inf, start, ed;
void add(int a, int b, int d, int c){
e[idx] = b;
cost[idx] = c;
w[idx] = d;
ne[idx] = h[a];
h[a] = idx;
idx++;
}
void dijkstra(int x){
fill(d, d+N, inf);
d[x] = 0;
heap.push({d[x], x});
while(heap.size()){
auto t = heap.top(); heap.pop();
int v = t.second;
if(st[v]) continue;
//cout << v << endl;
st[v] = true;
for(int i = h[v]; i != -1; i = ne[i]){
int j = e[i];
if(d[j] > d[v] + w[i]){
d[j] = d[v] + w[i];
heap.push({d[j], j});
pre[j].clear();
pre[j].push_back({v, i});
//printf("%d ---> %d %d\n", v, j, d[j]);
}
else if(d[j] == d[v] + w[i]){
pre[j].push_back({v, i});
//printf("%d ---> %d %d\n", v, j, d[j]);
}
}
}
return ;
}
void dfs(PII u){
if(u.first == start){
tmp.push_back(u);
//printf("push: %d %d\n", u.first, w[u.second]);
int c = 0;
for(int i = tmp.size()-1; i >= 1; i --){
c += cost[tmp[i].second];
//printf("cost: %d\n", c);
}
if(mincost > c) {
path = tmp;
mincost = c;
}
tmp.pop_back();
return ;
}
tmp.push_back(u);
//printf("push: %d %d\n", u.first, w[u.second]);
int j = u.first;
for(int i = 0; i < pre[j].size(); i++){
//printf("%d pre %d %d\n", j, pre[j][i].first, w[pre[j][i].second]);
dfs(pre[j][i]);
}
tmp.pop_back();
}
int main(){
memset(h, -1, sizeof h);
cin >> n >> m >> start >> ed;
for(int i = 0; i < m; i++){
int a, b, d, ct;
scanf("%d %d %d %d", &a, &b, &d, &ct);
add(a, b, d, ct);
add(b, a, d, ct);
}
dijkstra(start);
// 2*m+1是一条不存在的边,选用其主要是为了设置起点
dfs({ed, 2*m+1});
for(int i = path.size()-1; i >= 0; i --){
printf("%d ", path[i].first);
}
printf("%d %d", d[ed], mincost);
}
朴素dijkstra + dfs
#include <bits/stdc++.h>
using namespace std;
const int N = 505, inf = 0x3f3f3f3f;
bool st[N];
int g[N][N], cost[N][N], d[N];
int n, m, mincost = inf, start, ed;
vector<int> path, tmp, pre[N];
void dijkstra(int x){
fill(d, d+N, inf);
d[x] = 0;
while(true){
int v = -1;
for(int i = 0; i < n; i++){
if(!st[i] && (v == -1 || d[v] > d[i])){
v = i;
}
}
if(v == -1) break;
st[v] = true;
for(int i = 0; i < n; i ++){
if(d[i] > d[v] + g[v][i]){
d[i] = d[v] + g[v][i];
pre[i].clear();
pre[i].push_back(v);
}
else if(d[i] == d[v] + g[v][i]){
pre[i].push_back(v);
}
}
}
}
void dfs(int u){
if(u == start){
tmp.push_back(u);
int c = 0;
for(int i = tmp.size()-1; i > 0; i --){
int a = tmp[i], b = tmp[i-1];
c += cost[a][b];
}
if(mincost > c){
mincost = c;
path = tmp;
}
tmp.pop_back();
return ;
}
tmp.push_back(u);
for(int i = 0; i < pre[u].size(); i ++){
dfs(pre[u][i]);
}
tmp.pop_back();
}
int main(){
cin >> n >> m >> start >> ed;
memset(g, 0x3f, sizeof g);
for(int i = 0; i < m; i++){
int a, b, dis, c;
scanf("%d %d %d %d", &a, &b, &dis, &c);
g[a][b] = g[b][a] = dis;
cost[a][b] = cost[b][a] = c;
}
dijkstra(start);
dfs(ed);
for(int i = path.size()-1; i >= 0; i --){
printf("%d ", path[i]);
}
printf("%d %d", d[ed], mincost);
}
dijkstra
这题也可以直接在dijkstra的过程中选出最优解,无需通过dfs选。当两条路的距离相等时,优先选择花费少的那一条。
#include <bits/stdc++.h>
using namespace std;
const int N = 505, inf = 0x3f3f3f3f;
bool st[N];
int g[N][N], cost[N][N], d[N], ct[N],pre[N];
int n, m, mincost = inf, start, ed;
void dijkstra(int x){
fill(d, d+N, inf);
d[x] = 0;
while(true){
int v = -1;
for(int i = 0; i < n; i++){
if(!st[i] && (v == -1 || d[v] > d[i])){
v = i;
}
}
if(v == -1) break;
st[v] = true;
for(int i = 0; i < n; i ++){
if(d[i] > d[v] + g[v][i]){
d[i] = d[v] + g[v][i];
ct[i] = cost[v][i] + ct[v];
pre[i] = v;
}
else if(d[i] == d[v] + g[v][i] && ct[i] > cost[v][i] + ct[v]){
pre[i] = v;
ct[i] = cost[v][i] + ct[v];
}
}
}
}
void dfs(int u){
if(u == start){
printf("%d ", u);
return ;
}
dfs(pre[u]);
printf("%d ", u);
}
int main(){
cin >> n >> m >> start >> ed;
memset(g, 0x3f, sizeof g);
for(int i = 0; i < m; i++){
int a, b, dis, c;
scanf("%d %d %d %d", &a, &b, &dis, &c);
g[a][b] = g[b][a] = dis;
cost[a][b] = cost[b][a] = c;
}
dijkstra(start);
dfs(ed);
printf("%d %d", d[ed], ct[ed]);
}