[CodeForces20C]Dijkstra?(Prim, Dijkstra)

15 篇文章 0 订阅
4 篇文章 0 订阅

这道题只需要在计算最短路的时候, 记录当前最小边的端点即可, 用faz[]数组.

需要注意的是, 节点1只需要到节点N即可, 不需要整个图都联通. 可以用并查集, 也可以在Dijkstra算法后, 看一下dist[N](节点N到节点1的最短距离)是否为初值.

开始的时候, 我的第一个思路是建立一个最短路径生成树, 然后在遍历这颗树, 从1开始, 到N的路径只有一条.

但是我在提交的时候一直卡在了test 31, emmmm当即去看了别人的做法, 发现自己多走一步, 在求Dijkstra中就可以直接填充faz[]数组, 最后找到答案即可. 开始的做法确实需要很多的空间...

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
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<pair<ll, int> > pq;
    pq.push(make_pair(0, 1));
    dist[1] = 0;

    while(pq.size()){
        pair<ll, int> 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<int> 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数组一定要有, 当前最小边会在遍历边的时候被重复选择.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值