这道题只需要在计算最短路的时候, 记录当前最小边的端点即可, 用faz[]数组.
需要注意的是, 节点1只需要到节点N即可, 不需要整个图都联通. 可以用并查集, 也可以在Dijkstra算法后, 看一下dist[N](节点N到节点1的最短距离)是否为初值.
开始的时候, 我的第一个思路是建立一个最短路径生成树, 然后在遍历这颗树, 从1开始, 到N的路径只有一条.
但是我在提交的时候一直卡在了test 31, emmmm当即去看了别人的做法, 发现自己多走一步, 在求Dijkstra中就可以直接填充faz[]数组, 最后找到答案即可. 开始的做法确实需要很多的空间...
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int MAXN = 2e5 + 600;
typedef long long ll;
using namespace std;
struct Edge{
int to, next;
ll value;
bool operator<(const Edge & rhs) const{
return value < rhs.value;
}
} edges[MAXN << 1];
ll dist[MAXN];
int ihead[MAXN], ecnt;
int visited[MAXN];
int faz[MAXN];
int n, m;
int find(int x){
if(x == faz[x]){
return x;
}
int root = x, parent;
while(root != faz[root]){
root = faz[root];
}
while(x != root){
parent = faz[x];
faz[x] = root;
x = parent;
}
return root;
}
void merge(int x, int y){
x = find(x);
y = find(y);
faz[x] = y;
}
void addEdge(int u, int v, int value){
edges[++ecnt].to = v;
edges[ecnt].value = value;
edges[ecnt].next = ihead[u];
ihead[u] = ecnt;
}
void Dijkstra(){
memset(dist, 0x3f, sizeof(dist));
memset(faz, 0, sizeof(faz));
memset(visited, 0, sizeof(visited));
priority_queue > pq;
pq.push(make_pair(0, 1));
dist[1] = 0;
while(pq.size()){
pair p = pq.top();
pq.pop();
int u = p.second, v;
if(visited[u]){
continue;
}
visited[u] = 1;
for(int i = ihead[u]; i; i = edges[i].next){
v = edges[i].to;
if(dist[v] > dist[u] + edges[i].value){
dist[v] = dist[u] + edges[i].value;
faz[v] = u;
pq.push(make_pair(-dist[v], v));
}
}
}
stack s;
s.push(n);
int u = n;
while(faz[u]){
s.push(faz[u]);
u = faz[u];
}
while(s.size()){
printf("%d%c", s.top(), " \n"[s.size() == 1]);
s.pop();
}
}
int main(){
for(int i = 0; i < MAXN; ++i){
faz[i] = i;
}
scanf("%d%d", &n, &m);
int x, y, v;
for(int i = 0; i < m; ++i){
scanf("%d%d%d", &x, &y, &v);
addEdge(x, y, v);
addEdge(y, x, v);
if(find(x) != find(y)){
merge(x, y);
}
}
if(find(1) != find(n)){
printf("-1\n");
return 0;
}
Dijkstra();
return 0;
}
然后...Dijkstra单源最短路算法和Prim最小生成树算法都是运用了贪心思想.
并且算法的流程很像, 比如都可以用堆来优化.
需要注意的点是, 节点的visited数组一定要有, 当前最小边会在遍历边的时候被重复选择.